gpt4 book ai didi

linq - Entity Framework (4.2)HasRequired导致意外的LEFT OUTER JOIN

转载 作者:行者123 更新时间:2023-12-04 04:13:05 24 4
gpt4 key购买 nike

似乎在构造除已定义的第一个导航属性以外的导航属性的联接时, Entity Framework (NuGet的最新版本)可能会忽略HasRequired配置。

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

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);

Entity Framework 生成以下查询:
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也会发生这种情况。但是对于EF 1(.NET 3.5),不是。在EF 1中,每个Include(也是第一个)已映射到LEFT OUTER JOIN,也用于必需的关系。
  • 我认为不能说对于所需的导航属性来说,使用INNER JOIN是“正确的”,而LEFT OUTER JOIN是错误的。从映射的角度来看,使用什么都无关紧要,因为数据库中的约束可以正确表示模型中的关系。对于必需的导航属性,数据库中的FK列不能为空,并且数据库中必须存在一个约束,该约束强制FK引用目标表中的现有行。在这种情况下,无论您使用JOIN还是INNER JOIN,每个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-breaking-change-ef4-inner-joins-affect-eager-loading-many-to-many/
  • 我的理解是,此问题已得到解决,原因是在太多情况下引入了INNER JOIN以便在EF 4中快速加载。(也许在此阶段(EF 4的beta/候选版本),您的查询会EF团队对这个问题的答复:http://connect.microsoft.com/VisualStudio/feedback/details/534675/ef4-include-method-returns-different-results-than-ef1-include(我的粗体突出显示):

    We are fixing the issue for .net 4 RTM. This was an unintended breaking change. We did not make an intended change where every left outer join produced by an Include became an inner join in .Net 4. But rather the optimization looked at the constraints in the EF metadata and tried to convert those left outer joins which could be safely converted to inner joins based on the constraints. We had a bug in the code where we were reasoning based on the constraints which resulted in more aggressive conversion than what the constraints implied. We have scaled back the optimization so that we convert left outer joins to inner joins only in the places where we are absolutely sure we can do it based on the constraints. We think we can improve this optimization a little more in the future. You will start seeing more left outer joins for some queries in RTM when compared to RC and Beta 2 but in most of these cases this is needed to return correct results.



    因此,EF 4的最终发行版显然重新引入了更多的INNER JOIN(与beta/release候选版本相比),以避免类似的重大更改。

  • 抱歉,这不是一个真正的解释,而是一个古老的故事,为什么要先得到 LEFT OUTER JOIN然后再得到 INNER JOIN。如前所述,以这种方式编写查询并没有错-因为使用两个 LEFT OUTER JOIN或两个 INNER JOIN并没有错。我想只有EF团队才能确切解释您的查询为何生成该特定SQL。

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

    关于linq - Entity Framework (4.2)HasRequired导致意外的LEFT OUTER JOIN,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8527886/

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