为什么要使用左外连接?

11

有一个奇怪的问题。(也许根本不奇怪)

我有三个对象,Employee(员工),Rota(排班表)和Department(部门)。

public class Employee
{
    public int Id { get; set; }
    public String Name { get; set; }
    public virtual Department Department { get; set; }
}

internal class EmployeeMapping : EntityTypeConfiguration<Employee>
{
    public EmployeeMapping()
    {
        HasKey(a => a.Id);
        Property(a => a.Id).HasColumnName("UserId");

        HasRequired<Department>(a => a.Department).WithOptional().Map(a => a.MapKey("DepartmentId"));
    }
}

public class Department
{
    public int Id { get; set; }
    public String Name { get; set; }
}

internal class DepartmentMapping : EntityTypeConfiguration<Department>
{
    public DepartmentMapping()
    {
        HasKey(a => a.Id);
        Property(a => a.Id).HasColumnName("DepartmentId");
    }
}

public class Rota
{
    public int Id { get; set; }
    public virtual Employee Employee { get; set; }
    public virtual Department Department { get; set; }
}

internal class RotaMapping : EntityTypeConfiguration<Rota>
{
    public RotaMapping()
    {
        HasKey(a => a.Id);
        Property(a => a.Id).HasColumnName("RotaId");

        HasOptional<Employee>(a => a.Employee).WithOptionalDependent().Map(a => a.MapKey("EmployeeId"));
        HasOptional<Department>(a => a.Department).WithOptionalDependent().Map(a => a.MapKey("DepartmentId"));
    }
}

并不复杂。Rota可以分配给员工和/或部门,这些都是使用Fluent配置的。所有关联都正确(模式完美),但我有一个奇怪的异常。

当我执行myContext.Departments.FirstOrDefault()并查看生成的SQL时,Employee和Rota之间有一个 LEFT OUTER JOIN 。为什么会出现这种情况?
我不希望它这样做。也许我的Fluent映射不正确?我尝试了所有可能,但似乎找不出原因。如果我想要Rota对象,则理解为需要连接到Department。但反过来则不应该!

如果我执行myContext.Departments.AsNoTracking().FirstOrDefault(),它就不会做 LEFT OUTER JOIN's

有任何想法吗?

谢谢, D

3个回答

5
原因是错误的映射。看起来是正确的,但实际上并不是。请使用以下内容代替:
internal class EmployeeMapping : EntityTypeConfiguration<Employee>
{
    public EmployeeMapping()
    {
        HasKey(a => a.Id);
        Property(a => a.Id).HasColumnName("UserId");

        HasRequired<Department>(a => a.Department).WithMany()
                                                  .Map(a => a.MapKey("DepartmentId"));
    }
}

internal class RotaMapping : EntityTypeConfiguration<Rota>
{
    public RotaMapping()
    {
        HasKey(a => a.Id);
        Property(a => a.Id).HasColumnName("RotaId");

        HasOptional<Employee>(a => a.Employee).WithMany()
                                              .Map(a => a.MapKey("EmployeeId"));
        HasOptional<Department>(a => a.Department).WithMany()
                                                  .Map(a => a.MapKey("DepartmentId"));
    }
}

当创建数据库并且数据库看起来正确时,您的映射被正确解析,但EF认为您将所有关系都映射为一对一。这会让EF感到困惑,并生成用于创建内部实体引用的一对一查询。当您告诉EF从属实体是可选的时,这些左连接对于一对一关系是必要的 - EF不知道它们是否存在,除非它加载它们的键。


好的,这确实解决了问题,谢谢!但是我不确定为什么。也许我在这里有一个全局误解。但是,HasOptional().WithMany()肯定意味着0.1->Many吗? - Dean Thomas
嗯,那很奇怪。因为它只是一个0..1到1的关系。或者我完全误解了关系? - Dean Thomas
我认为你并没有一对一(one-to-one)关系。这意味着一个部门只能有一个单一的员工,等等。而且,要定义这种类型的一对一关系,你需要在数据库中拥有唯一键,并且EF目前还不支持它们。 - Ladislav Mrnka
你说得对,谢谢你的帮助,我太傻了 :-) - Dean Thomas

0

我绝不是专家,只是猜测而已。但你可以尝试按照实体框架的方式查询,然后再按照理想中的方式查询,并发布时间差异。也许实体框架在这方面有所发现,但我表示怀疑。


0

我有一个理论。当你关闭更改跟踪时,左外连接会消失。同时,Employee和Rota都引用了Department。

因此,我的理论是,在启用更改跟踪的情况下,实体框架尝试加载所有具有对部门的引用的实体,以防需要级联更新部门。

换句话说,它认为对部门的更改可能会导致对引用该部门的Employee或Rota的更改,因此它会加载所有内容以防万一。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接