首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何避免实体框架TPT继承中的多态行为以有效查询基类型

如何避免实体框架TPT继承中的多态行为以有效查询基类型
EN

Stack Overflow用户
提问于 2012-12-05 11:58:22
回答 1查看 1.8K关注 0票数 4

概述

我首先使用实体框架4.3代码和fluent接口来设置我的DbContext。我有一个基项类,它具有继承此类的其他类型,例如事件、BlogPost、ForumThread、WikiPage等等。

这些继承类型与我认为实体框架所指的TPT继承相映射。这在查询单个类型(如“events”或“blog post”)时非常有用,但在尝试跨所有类型查询时,会构造非常复杂的查询,性能非常糟糕,因为为了实现EF提供的多态行为而需要连接。

问题上下文

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

码第一模型

代码语言:javascript
运行
复制
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似乎不喜欢这样。目前我手头上没有错误,但我在简单映射方面的尝试失败了。

替代解决方案?

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

我最喜欢的解决方案是在代码中,而不是数据库触发器/存储过程中。

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

更新

在通过Nuget (针对EntityFramework 4.0)更新到.Net 5之后,我已经能够通过它们的标记查询条目,并将其投影到一个新的SearchItem中,这将产生相当干净的SearchItem,而无需加入TPT类型。

代码语言:javascript
运行
复制
        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

代码语言:javascript
运行
复制
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无法翻译的查询。有办法解决这个问题吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-12-05 13:10:07

是否有一种方法来构造查询以强制EF只返回基类型而不是多态类型,这会导致太多的连接和糟糕的性能?

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

理论上,您应该能够将Items和项目查询到您的非映射 POCO类,只需从基类中获取您想要的属性。不幸的是,这在.NET 4.0 - EF仍然执行连接中行不通。您可以在.NET 4.5和EF5.0中尝试这一点,其中问题是应该解决

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13722780

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档