实体框架(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 JOIN
FK 是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 JOIN
s(与测试版/候选发布版相比)以避免类似的重大更改。
抱歉,这更多的是一个历史故事,而不是真正的解释为什么你会得到一个INNER JOIN
然后一个LEFT OUTER JOIN
。如前所述,以这种方式编写查询并没有错 - 因为使用两个查询也不会错INNER JOIN
一两个LEFT OUTER JOIN
s。我猜想只有 EF 团队才能准确解释为什么您的查询会产生特定的 SQL。
我建议 - 如果您没有遇到严重的性能问题 - 不要担心该 SQL(因为您得到的结果毕竟是正确的)并继续。不喜欢 EF 创建的 SQL 最终会导致编写大量功能和更改请求,或者编写大量原始 SQL 查询,或者根本放弃 EF。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)