Linq 实体框架(4.2)在意外的左外部联接中具有必需的结果
实体框架(NuGet的最新版本)似乎在为导航属性(定义的第一个属性除外)构造连接时忽略了HasRequired配置 例如,给定具有以下配置的POCO对象(人员):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
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中对某些
s使用Include
s的更改并不是因为EF1中的SQL错误,而是为了创建更好、更高性能的SQL。此更改实际上引入了一个突破性的更改,即一些查询现在返回的结果与EF 1中的结果不同:internaljoin
- 我的理解是,这已经被修复,原因是在太多的情况下,
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]