Entity Framework 在一对一(可选/必需)关系中生成第二个左连接

问题描述 投票:0回答:1

我在 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]

为什么 Entity Framework 有一个额外的(无用的)左连接用于这种类型的关系?

c# entity-framework ef-code-first entity-framework-4.2
1个回答
3
投票

当你有一对一的关系时,即使你没有明确

.Include
相关的实体,实体框架也会创建一个连接语句。

在您的情况下,第一个连接来自

.Include
语句,默认情况下添加另一个左外部连接。您可以通过删除 include 语句并观察将生成“Required”左外连接语句的 SQL 输出来检查这一点(实体框架需要它来验证对象模型是否正确)。

此外,从 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 =&gt; e.Level1Reference.Level2Reference)

出现这种情况时,它会生成“required”的join,然后为Level1Reference生成join。然后它需要生成一个连接:

  1. “required”加入Level2Reference
  2. 包含 Level2Reference

此问题的一个解决方法是使用 LINQ 语法并将数据库键公开为对象模型的属性。执行此操作时,您实际上覆盖了对象导航语法并手动告诉 EF 如何构建连接。由于它没有查找如何使用您的 Fluent 对象模型构建连接,因此它别无选择,只能按照您的连接说明进行操作。 (这是当时的项目经理 Diego Vega 给我的大概解释,当时我们提交了几个关于重复/不必要连接的错误)。

© www.soinside.com 2019 - 2024. All rights reserved.