实体框架在一对一(可选/必需)关系中生成第二个左联接
本文关键字:第二个 关系 一对一 框架 可选 必需 实体 | 更新日期: 2023-09-27 18:28:46
我在EF Code First中有以下模型:
public class A
{
public int Id { get; set; }
public virtual B { get; set; }
}
public class B
{
public int Id { get; set; }
public virtual A { get; set; }
}
我将关系定义如下:
modelBuilder.Entity<A>().HasKey(entity => entity.Id);
modelBuilder.Entity<B>().HasKey(entity => entity.Id);
modelBuilder.Entity<A>()
.HasOptional(entity => entity.B)
.WithRequired(entity => entity.A);
当我写下以下查询时:
var a = db.AItems.Include("B");
生成的查询如下:
SELECT
[Extent1].[Id] AS [Id],
[Extent3].[Id] AS [Id1]
FROM [dbo].[As] AS [Extent1]
LEFT OUTER JOIN [dbo].[Bs] AS [Extent2] ON [Extent1].[Id] = [Extent2].[Id]
LEFT OUTER JOIN [dbo].[Bs] AS [Extent3] ON [Extent2].[Id] = [Extent3].[Id]
为什么实体框架对于这种类型的关系有一个附加的(无用的)左联接?
当您有一对一的关系时,即使您没有显式.Include
相关实体,实体框架也会创建一个联接语句。
在您的情况下,第一个联接来自.Include
语句,默认情况下会添加另一个左侧外部联接。您可以通过删除include语句并观察SQL输出来检查这一点;"必需";left外部联接语句(实体框架需要它来验证对象模型是否正确)。
此外,从EF 6.4开始,如果您的查询是:,则无法避免重复联接
Set<Parent>
.Include(x => x.RequiredChild.OptionalGrandChild)
.ToList();
因为,.Include
的XML文档注意到:
/// To include a reference and then a reference one level down: query.Include(e => e.Level1Reference.Level2Reference)
当这种情况发生时;"必需";join,然后为Level1Reference生成一个join。然后它需要为生成一个联接
- ";"必需";联接Level2Reference
- Include Level2Reference
解决此问题的一种方法是使用LINQ语法,并将数据库键作为对象模型上的属性公开。当您这样做时,您可以有效地覆盖对象导航语法,并手动告诉EF如何构建联接。由于它没有查找如何使用Fluent对象模型构建联接,因此它别无选择,只能遵循联接说明。(这是当时的项目经理Diego Vega给我的大致解释,当时我们提交了几个关于重复/不必要联接的错误)。