实体框架 (4.2) HasRequired 导致意外的 LEFT OUTER JOIN

2023-11-23

实体框架(NuGet 的最新版本)似乎在为导航属性(而不是定义的第一个属性)构造联接时可能会忽略 HasRequired 配置。

例如,给定一个具有以下配置的 POCO 对象(Person):

var person = modelBuilder.Entity<Person>();
person.ToTable("The_Peoples");
person.HasKey(i => i.Id);
person.Property(i => i.Id).HasColumnName("the_people_id");
person.HasRequired(i => i.Address)
    .WithMany()
    .Map(map => map.MapKey("address_id"));
person.HasRequired(i => i.WorkPlace)
    .WithMany()
    .Map(map => map.MapKey("work_place_id"));

我正在尝试使用以下查询加载人员列表:

myContext.Set<People>()
    .Include(o => o.Address)
    .Include(o => o.WorkPlace);

实体框架生成以下查询:

FROM  [dbo].[The_Peoples] AS [Extent1]
INNER JOIN [dbo].[The_Addresses] AS [Extent2] ON [Extent1].[address_id] = [Extent2].[address_id]
LEFT OUTER JOIN [dbo].[The_Work_Places] AS [Extent3] ON [Extent1].[work_place_id] = [Extent3].[work_place_id]

请注意,到 *The_Addresses* 表的联接是内部联接(如预期),但是,到 *The_Work_Places* 的后续联接是外部联接。鉴于 Address 和 WorkPlace 属性均已标记为必需,我希望这两个联接都是内部联接。我还尝试使用“Required”属性标记“Address”和“WorkPlace”属性,但这没有效果。

这是一个错误还是我可能配置错误?建议?


您的模型配置是正确的,我认为这不是一个错误,而是设计的行为,但我无法确切地说出什么设计。我也在此类查询中看到过该 SQL。仅作几点说明:

  • 您看到的查询并非特定于 EF 4.2。 EF 4.1 和 EF 4.0 也会出现这种情况。但not对于 EF 1 (.NET 3.5)。在 EF 1 中,每Include,也是第一个,已被映射到LEFT OUTER JOIN,也适用于所需的关系。

  • 我认为人们不能说使用INNER JOIN对于所需的导航属性来说是“正确的”并且LEFT OUTER JOIN是错的。从映射的角度来看,只要数据库中的约束正确表示模型中的关系,您使用什么并不重要。对于所需的导航属性,数据库中的 FK 列不能为空,并且数据库中必须有一个约束,强制 FK 引用目标表中的现有行。如果是这样的话,每一个JOIN必须返回一行,无论您是否使用INNER JOIN or LEFT OUTER JOIN.

  • 如果模型和数据库在关系方面“不同步”,会发生什么?基本上这两种情况都会发生无意义的情况:如果你使用LEFT OUTER JOINFK 是NULL在数据库中或引用不存在的行,您将得到一个导航属性为的实体null,违反了该属性所需的模型定义。使用INNER JOIN并不是更好:你根本得不到任何实体,查询结果至少与结果一样错误LEFT OUTER JOIN,如果不是更糟的话。

  • 所以,我认为 .NET 4 中的更改要使用INNER JOIN对某些人来说Include这样做并不是因为 EF 1 中的 SQL 错误,而是为了创建更好、性能更高的 SQL。此更改实际上引入了重大更改,因为某些查询现在返回的结果与 EF 1 中的结果不同:http://thedatafarm.com/blog/data-access/ef4-writing-change-ef4-inner-joins-affect-eager-loading-many-to-many/

  • 我的理解是这个问题已经解决了,原因是INNER JOIN在太多情况下,EF 4 中引入了急切加载。(也许在这个阶段(EF 4 的测试版/发布候选版)您的查询将有两个INNER JOIN是。)EF 团队对此问题的回复:http://connect.microsoft.com/VisualStudio/feedback/details/534675/ef4-include-method-returns- different-results-than-ef1-include(我的大胆强调):

    我们正在修复 .net 4 RTM 的问题。这是一个无意的 突破性的改变。我们没有做出有意的改变,让每个人都离开 由 Include 生成的外连接成为 .Net 4 中的内连接。但 相反,优化着眼于 EF 元数据中的约束 并尝试转换那些可以安全地进行的左外连接 根据约束转换为内连接。我们有一个错误 我们根据所产生的约束进行推理的代码 比约束所暗示的更积极的转换。我们 缩减了优化,以便我们转换左外连接 仅在我们绝对确定可以的地方进行内连接 根据限制去做。我们认为我们可以改进这一点 以后再优化一点。你会开始看到更多 与 RC 和 Beta 相比,RTM 中某些查询的左外连接 2 但在大多数情况下,需要这样做才能返回正确的结果。

    因此,EF 4 的最终版本显然重新引入了更多内容LEFT OUTER JOINs(与测试版/候选发布版相比)以避免类似的重大更改。

抱歉,这更多的是一个历史故事,而不是真正的解释为什么你会得到一个INNER JOIN然后一个LEFT OUTER JOIN。如前所述,以这种方式编写查询并没有错 - 因为使用两个查询也不会错INNER JOIN一两个LEFT OUTER JOINs。我猜想只有 EF 团队才能准确解释为什么您的查询会产生特定的 SQL。

我建议 - 如果您没有遇到严重的性能问题 - 不要担心该 SQL(因为您得到的结果毕竟是正确的)并继续。不喜欢 EF 创建的 SQL 最终会导致编写大量功能和更改请求,或者编写大量原始 SQL 查询,或者根本放弃 EF。

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

实体框架 (4.2) HasRequired 导致意外的 LEFT OUTER JOIN 的相关文章

随机推荐