小编典典

在不使用导航属性的情况下添加相关实体

sql

我有以下用于测试的类:

public class Company
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public string Name { get; set; }
}

public class Employee
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public string Name { get; set; }

    public int CompanyId { get; set; }
    public virtual Company Company { get; set; }
}

public class EFTestDbContext : DbContext
{
    public DbSet<Employee> Employees { get; set; }
    public DbSet<Company> Companies { get; set; }
}

为了进行测试,我想通过一次SaveChanges调用插入一家公司和该公司的一名员工,如下所示:

Company company = new Company
{
    Name = "Sample company"
};

context.Companies.Add(company);

// ** UNCOMMENTED FOR TEST 2
//Company company2 = new Company
//{
//    Name = "Some other company"
//};
//context.Companies.Add(company2);

Employee employee = new Employee
{
    Name = "Hans",
    CompanyId = company.Id
};
context.Employees.Add(employee);

context.SaveChanges();

即使我没有使用导航属性,而是通过Id建立了联系,但这种方式还是神秘地起作用了-
员工用正确的外键保存了公司的外键,该公司的外键从0更新为实际值,这使我走了出去!一些隐藏的C#功能?

然后,我决定添加更多代码,上面的代码段中对此进行了注释,使其插入了2个Company实体和1个Employee实体,然后出现异常:

无法确定“ CodeLab.EFTest.Employee_Company”关系的主要结尾。多个添加的实体可能具有相同的主键。

这是否意味着在外键为0且在同一SaveChanges事务中插入单个匹配实体的情况下,实体框架将假定外键应用于该匹配实体?

在第二项测试中,当有两个匹配关系类型的实体时,实体框架将引发异常,因为它无法确定应与哪个公司雇员相关。

编辑:

我又做了一个测试,并注释了一行。第一个测试仍然可以正常运行(因为int的默认值为0):

Employee employee = new Employee
{
    Name = "Hans",
    //CompanyId = company.Id // * no need for this at all
};

阅读 156

收藏
2021-04-28

共1个答案

小编典典

您并没有真正找到隐藏的C#功能,也许是不起眼的Entity Framework功能。

当您分配时CompanyId,EF知道Id = 0(当时)拥有的公司是员工的母公司。在很多情况下,EF执行DetectChanges,它还会执行
关系修正 :匹配外键值和引用。执行时会发生这种情况

context.Employees.Add(employee);

现在,EF将使用引用而不是外键值,因此它知道要在数据库中存储哪个FK值。

当您创建两家公司时,有两个实例具有相同的临时键值,因此EF无法再选择了。

因此,当您要存储新的连接对象时,始终建议您设置引用而不是FK值。

2021-04-28