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

2024-04-23

Overview

我首先使用实体​​框架 4.3 代码和流畅的界面来设置我的 DbContext。我有一个基地Item具有继承此类型的其他类型的类,例如Event, BlogPost, 论坛主题, WikiPage等等。

这些继承的类型与我认为实体框架所指的 TPT 继承进行映射。在查询“事件”或“博客文章”等单一类型时,这非常有效,但在尝试跨所有类型进行查询时,由于为了实现 EF 提供的开箱即用的多态行为而需要连接,因此会构造非常复杂的查询,并且性能很差。

问题背景

我想构建一个全局搜索功能,我只需要访问基本的“Item”实体,而不是继承的实例。我希望能够按名称、标签等查询基本项目类。执行任何类型的 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 仅返回基本类型而不是多态类型,从而导致过多的连接和糟糕的性能?或者还有其他聪明的方法来解决这个问题吗?

Update

通过 Nuget 更新到 EntityFramework 5(针对 .Net 4.0)后,我已经能够通过项目的标签查询项目并将其投影到新的项目中搜索项目这会产生相当干净的 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 无法转换的查询。有解决方法吗?


有没有办法构造一个查询来强制 EF 仅返回 基类型而不是多态类型会导致太多 加入和糟糕的表现?

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

理论上你应该能够查询Items并投影到你的未映射的POCO 类仅包含您想要从基类中获取的属性。不幸的是,这在 .NET 4.0 中不起作用 -EF 仍然执行连接 http://blogs.msdn.com/b/adonet/archive/2010/08/17/performance-considerations-when-using-tpt-table-per-type-inheritance-in-the-entity-framework.aspx。您可以在 .NET 4.5 和 EF 5.0 中尝试此问题应该解决 http://thedatafarm.com/blog/data-access/entity-framework-june-2011-ctp-tpt-inheritance-query-improvements/.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何避免实体框架 TPT 继承中的多态行为,以便有效地查询基类型 的相关文章

随机推荐

  • 与枚举和可选元组关联值进行 Swift 模式匹配

    我目前正在使用 Alamofire 并使用枚举来描述我按照自述文件中的建议使用的 API 端点表示如下 public enum API case GetStops stopCode String case GetPhysicalStops
  • 2个JS函数同名冲突

    Short 在同一页面使用 2 个库 jQuery UI 和 Twitter Bootstrap jQuery UI 对我来说非常重要 因为几乎所有的 UI 东西都是基于它构建的 Twitter Bootstrap 仅适用于带下拉菜单的拆分
  • 如何通过拖动扩展窗口框架来使 WPF 窗口可移动?

    在 Windows 资源管理器和 Internet Explorer 等应用程序中 人们可以抓住标题栏下方的扩展框架区域并拖动窗口 对于 WinForms 应用程序 窗体和控件尽可能接近本机 Win32 API 一个人会简单地覆盖WndPr
  • 总和投影和结果约束

    我在数据库中有 100 个实体 我想获取前 20 个实体的某些属性的总和 Criteria cr getSession createCriteria Entity class cr setFirstResult 0 cr setMaxRes
  • ggplot 中的躲避/替换/排斥轴刻度标签?

    如果没有大量工作 我想要的可能是不可能的 但也许有人有解决方案 我有一个如下图 当然这是一个过于简单的示例 其中我的刻度标签彼此非常接近 dd lt data frame x 1 4 y c 10 10 5 10 6 10 7 z LETT
  • python 如何在嵌套列表中搜索项目

    假设我有这个清单 li 0 20 ar 20 40 asdasd 50 199 bar 24 69 sarkozy 现在 忘掉数字吧 它们让我能够识别字符串的位置 所以基本上 鉴于我手头有字符串 ar 我如何提取包含 ar 的所有列表 ne
  • 将 MATLAB 单元格类型转换为 C++

    我正在使用 C 转换 MATLAB 程序犰狳 http arma sourceforge net docs html syntax对于矩阵代数 我被困住了cell http blogs mathworks com loren 2006 06
  • wxGrid 在右侧显示大的空白边框

    默认情况下 wxGrid 在最后一列之后的右侧显示一个小的 10 像素 空白边框 调用 SetMargins 对其没有任何影响 这很烦人 但我可以忍受 但是 如果我将行标签宽度设置为零 则空白边框会变得更大 如果我只有一列 效果会很糟糕 看
  • 送达收据请求不适用于 XMPP Android (aSmack)

    我正在使用 OpenFire 和 aSmack 我似乎无法让 送货收据 正常工作 创建连接时我执行以下操作 create connection connection login username password DeliveryRecei
  • c++ 打开文件的问题

    必须是一个简单的答案 但我不知所措 这是返回错误的代码 我尝试过带或不带起始斜杠 我不知道完整路径 我希望它是相对于exe的 这就是相对路径 我试图逃避斜线 我的问题是当文件存在时我收到 打开文件时出错 为什么它失败了 ifstream m
  • 如何编写恒定时间函数将最高有效位复制到所有位

    我想用 C 语言编写一个函数 它采用以下的 MSBuint8 t 如果已设置 则返回0xFF如果不0x00 简而言之 它返回一个整数 其中所有位都设置为与 MSB 相同的值 但我想以完全恒定的时间方式来完成它 没有分支 没有数组偏移 只是数
  • jq - 过滤器数组不包含

    我正在使用应用程序 jq 从命令行过滤 json 文件 https stedolan github io jq https stedolan github io jq 这是一个代表问题的糟糕例子 如何过滤该集合以包含所有非红色或非圆形的水果
  • 如何循环遍历文件来获取数据?

    我正在尝试进行基本登录并注册 C 控制台应用程序 但是 我需要循环遍历我的文件以查看用户输入的用户名和密码在登录时是否匹配 如果用户输入用户名和密码 我希望我的代码遍历我的文件以检查它是否是现有的用户名和密码 这是我的代码 Serializ
  • Pandas:将列转换为列表

    我有一个数据框 date member id val 2016 06 01 2377264 14 2016 06 01 289719 6 2016 06 02 289719 12 2016 06 02 2377264 1 2016 06 0
  • 如何更改 ng-repeat 中单个元素的 ng-click 行为?

    我正在重构一个用角度编写的表格 目前 ng repeat 用于创建多个表行 其中任何行在单击时都会重定向到给定的 ui sref tbody tr class tablebox content td class name user name
  • JAVA JNI C 调试器

    是否有任何调试器可以帮助调试 Java JNI 程序以及 C 库 我应该能够在Java中从static void main开始调试程序 并继续调试并在本机c函数中放置断点 然后在控制权从C转移到Java后继续在Java中调试 Java 虚拟
  • 在运行时执行 C# 或 VB.NET 代码

    最近在 Codility com 上花了一些时间 我突然想到了这个问题 它们如何执行您创建的代码 特别是与 C 和 VB NET 有关的代码 我基本上想知道的是 如何在表单上的文本框中输入一些代码 然后运行该代码 如果没有第三方工具 这可能
  • 为 Windows 开发计划任务

    我必须使用 C net 开发一个必须每天运行一次的应用程序 它最多只运行一分钟 因此开发 Windows 服务有点大材小用 计划任务是合适的方法 但是 我对应用程序如何传达其结果有一些疑问 如何向任务调度程序指示任务失败 这是通过程序的退出
  • 查找包含“inf”或“nan”的项目的索引

    以下是一个示例1 item在我的清单中 array 1 2 3 43 83 92 12 54 93 23 94 83 23 inf inf inf inf inf 83 33 33 83 13 83 83 nan 83 73 43 43 4
  • 如何避免实体框架 TPT 继承中的多态行为,以便有效地查询基类型

    Overview 我首先使用实体 框架 4 3 代码和流畅的界面来设置我的 DbContext 我有一个基地Item具有继承此类型的其他类型的类 例如Event BlogPost 论坛主题 WikiPage等等 这些继承的类型与我认为实体框