gpt4 book ai didi

inheritance - 如何避免 Entity Framework TPT 继承中的多态行为以有效查询基类型

转载 作者:行者123 更新时间:2023-12-04 03:01:47 25 4
gpt4 key购买 nike

概览

我首先使用实体​​框架 4.3 代码和流畅的界面来设置我的 DbContext。我有一个基 Item 类,其中包含继承它的其他类型,例如 Event、BlogPost、ForumThread、WikiPage 等。

这些继承的类型与我认为 Entity Framework 所指的 TPT 继承相映射。这在查询诸如“事件”或“博客文章”之类的单一类型时非常有效,但在尝试跨所有类型进行查询时,由于需要连接以实现 EF 提供的开箱即用的多态行为,因此构建了性能非常复杂的查询.

问题上下文

我想构建一个全局搜索功能,我只需要访问基本的“项目”实体而不是继承的实例。我希望能够通过名称、标签等跨基本项目类进行查询。执行任何类型的 LINQ 查询,即使在请求基本项类型时仍会导致多态行为,从而降低性能。

代码优先模型

public class Item
{
public int Id { get; set; }

public string Name { get; set; }

public string Body { get; set; }

public DateTime Created { get; set; }

public int? CreatedBy { get; set; }

public int? LastModifiedBy { get; set; }

public DateTime? LastModified { get; set; }

public virtual User Author { get; set; }

public bool IsDeleted { get; set; }

public string ImageUri { get; set; }

public virtual ICollection<Tag> Tags { get; set; }
}

public class Event : Item
{
// Additional properties
}

public class BlogPost : Item
{
// Additional properties
}

我希望能够做的是将另一个 POCO 映射到同一个基表,这样当我在其上构造查询时,它不涉及继承问题。不过,EF 似乎并不喜欢这个。目前我手头没有错误,但我尝试简单映射失败。

替代解决方案?
  • 我曾想过实现一个类似于“项目”表的“索引”表,并在创建新项目类型时向其中插入一条记录。但是,每当事件、博客文章数据发生变化等时,此索引数据也需要更新。外键(例如标签)使这进一步复杂化。每当标签上说一个事件发生更改时,我必须确保这些更改也在匹配的索引表上同步。当考虑所有不同的项目类型时,这将成为管理的噩梦,坦率地说,这似乎不是一个非常优雅的解决方案。
  • 数据库触发器

  • 我的首选解决方案是代码中的解决方案,而不是数据库触发器/存储过程。

    有没有办法构造一个查询来强制 EF 只返回基类型而不是多态类型,这会导致太多连接和糟糕的性能?或者有没有其他聪明的方法来解决这个问题?

    更新

    通过 Nuget(针对 .Net 4.0)更新到 EntityFramework 5 后,我已经能够通过它们的标签查询项目并将项目投影到一个新的 SearchItem 中,这会产生相当干净的 SQL,而无需连接到 TPT 类型。
            var x = from item in repository.FindAll<Item>()
    where item.Tags.Any(t => t.Name == "test")
    select new SearchItem
    {
    Id = item.Id,
    Name = item.Name,
    Body = item.Body,
    Created = item.Created,
    CreatedBy = item.CreatedBy,
    IsDeleted = item.IsDeleted,
    ImageUri = item.ImageUri,
    MembershipEntityId = item.MembershipEntityId,
    //Tags = (from t in item.Tags
    // select new Tag
    // {
    // Id = t.Id,
    // Name = t.Name,
    // MembershipEntityId = t.MembershipEntityId
    // })
    };

    SQL
    SELECT 
    [Extent1].[Id] AS [Id],
    [Extent1].[Name] AS [Name],
    [Extent1].[Body] AS [Body],
    [Extent1].[Created] AS [Created],
    [Extent1].[CreatedBy] AS [CreatedBy],
    [Extent1].[IsDeleted] AS [IsDeleted],
    [Extent1].[ImageUri] AS [ImageUri],
    [Extent1].[MembershipEntityId] AS [MembershipEntityId]
    FROM [dbo].[Item] AS [Extent1]
    WHERE EXISTS (SELECT
    1 AS [C1]
    FROM [dbo].[ItemTag] AS [Extent2]
    INNER JOIN [dbo].[Tag] AS [Extent3] ON [Extent3].[Id] = [Extent2].[Tag_Id]
    WHERE ([Extent1].[Id] = [Extent2].[Item_Id]) AND (N'test' = [Extent3].[Name])
    )

    这解决了我一半的问题,因为我现在可以按标签搜索基本类型。但是,我希望能够使用新投影返回标签。包括注释掉的代码会导致 EF 无法翻译的查询。有解决方法吗?

    最佳答案

    Is there a way to construct a query to force EF to only return the base type instead of the polymorphic type which results in too many joins and horrible performance?



    一般没有。你已经映射了继承,如果你想返回 Item 的实例, EF 必须始终返回正确的类型 => 它需要这些连接。 EF 也不允许多次映射同一个表,因此您不能在同一个映射中使用 Item再次映射为另一个 POCO。

    理论上你应该可以查询 Items并转换到您的 未映射 POCO 类只有您想要从基类中获得的属性。不幸的是,这在 .NET 4.0 中不起作用 - EF still performed joins .您可以在 .NET 4.5 和 EF 5.0 中尝试此问题,其中此问题 should be solved .

    关于inheritance - 如何避免 Entity Framework TPT 继承中的多态行为以有效查询基类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13722780/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com