Linq 实体框架(4.2)在意外的左外部联接中具有必需的结果

Linq 实体框架(4.2)在意外的左外部联接中具有必需的结果,linq,entity-framework,include,dbcontext,Linq,Entity Framework,Include,Dbcontext,实体框架(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

实体框架(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"));
请注意,到*the_Addresses*表的连接是一个内部连接(如预期),但是,到*the_Work_Places*的后续连接是一个外部连接。鉴于Address和WorkPlace属性都标记为required,我希望这两个连接都是内部连接。我还尝试用Required属性标记Address和WorkPlace属性,但没有效果


这是一个bug还是我可能误解了什么?建议?

您的模型配置是正确的,我认为这不是一个bug,而是设计的行为,但我无法确切说出是什么设计。我也在这些查询中看到了SQL。只有几句话:

  • 您看到的查询不是EF 4.2特有的。EF 4.1和EF 4.0也会出现这种情况。但对于EF 1(.NET 3.5)而言,不是。在EF 1中,每个
    包含
    ,也是第一个,都已映射到
    左侧外部连接
    ,也用于所需的关系

  • 我认为不能说使用
    内部连接
    对于所需的导航属性是“正确的”,而
    左侧外部连接
    是错误的。从映射的角度来看,使用什么并不重要,因为数据库中的约束正确地表示了模型中的关系。对于所需的导航属性,数据库中的FK列不能为Null,并且数据库中必须存在强制FK引用目标表中现有行的约束。如果是这种情况,则无论是使用
    内部联接
    还是
    左侧外部联接
    ,每个
    联接都必须返回一行

  • 如果模型和数据库在关系方面“不同步”,会发生什么情况?在这两种情况下基本上都会发生无意义的情况:如果使用
    左外部联接
    ,并且FK在DB中为
    NULL
    ,或者引用不存在的行,则会得到一个实体,其中导航属性为
    NULL
    ,违反了需要该属性的模型定义。使用
    内部联接
    并不是更好:您根本不会得到实体,查询结果至少与
    左侧外部联接
    的结果一样错误,如果不是更糟的话

  • 因此,我认为.NET4中对某些
    Include
    s使用
    internaljoin
    s的更改并不是因为EF1中的SQL错误,而是为了创建更好、更高性能的SQL。此更改实际上引入了一个突破性的更改,即一些查询现在返回的结果与EF 1中的结果不同:

  • 我的理解是,这已经被修复,原因是在太多的情况下,
    内部连接
    s被引入EF4中的急切加载。(可能在这个阶段(EF 4的beta/发布候选)您的查询会有两个
    内部连接
    s。)EF团队对该问题的回答:(我用粗体突出显示):

    我们正在解决.net 4 RTM的问题。这是一场意外 零钱我们没有在每个人都离开的地方做出预期的改变 包含生成的外部联接成为.Net 4中的内部联接。但是 相反,优化着眼于EF元数据中的约束 并试图转换那些可以安全使用的左外连接 已转换为基于约束的内部联接。我们的房间里有个虫子 我们根据产生的约束进行推理的代码 在更积极的转换比什么约束暗示我们 已缩小优化范围,以便转换左外部联接 只有在我们绝对确信我们能做到的地方,才能进行内部连接 根据限制条件进行操作。我们认为我们可以改进这一点 以后再优化一点您将开始看到更多内容 与RC和Beta相比,RTM中某些查询的左外部联接 2但在大多数情况下,这是返回正确结果所必需的。

    因此,EF4的最终版本显然重新引入了更多的
    左外连接
    s(与beta/发布候选版本相比),以避免像这样的破坏性更改

很抱歉,这与其说是一个真实的解释,不如说是一个历史故事,不如说是一个真实的解释,为什么会得到一个
内部连接
,然后是一个
左外部连接
。如上所述,以这种方式编写查询并没有错——因为使用两个
内部联接
s或两个
左外部联接
s也不会错。我想只有EF团队才能确切地解释为什么您的查询会生成特定的SQL


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

这就像是一个neckro,但今天我遇到了同样的问题

这方面的问题是:

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]

当您应用来自
[dbo].[The_Peoples]
的筛选器时,您将其指定为将筛选器应用于联接,因此花费的时间更少,但我们发现(您可以运行查询计划查看此问题)它将联接到表的全部内容,然后稍后应用筛选器。。这就需要很多额外的时间。。在我们的例子中,它会触发一个超时,一个需要1到3秒的查询需要1分钟以上的时间

尝试在数据库中使用
WithRequiredDependent()
而不是
WithMany()

,\u Peoples.work\u place\u id是否标记为非空?如果是,那么连接是外部的还是内部的有关系吗
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]
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]