不使用导航属性添加相关实体

时间:2014-06-06 20:49:35

标签: c# sql entity-framework

我有以下类,设置为测试:

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 x Company实体和1 x Employee实体,然后我得到例外:

  

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

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

在第二个测试中,当有两个实体匹配关系类型时,实体框架会抛出一个异常,因为它无法确定哪个公司员工应该与之相关。

修改

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

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

2 个答案:

答案 0 :(得分:5)

您并没有真正触及隐藏的C#功能,可能是一个模糊的实体框架功能。

当您分配CompanyId时,EF知道拥有Id = 0(当时)的公司是员工的父母。在很多情况下,EF executes DetectChanges也会执行 relationship fixup :匹配外键值和引用。执行

时会发生这种情况
context.Employees.Add(employee);

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

当您创建两家公司时,有两个实例具有相同的临时密钥值,因此EF不能再选择。

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

答案 1 :(得分:2)

您已将公司添加到公司表中。

context.Companies.Add(company);

然后设置员工的companyId:

CompanyId = company.Id

这是在sql中创建关系所需的全部内容。可能实体框架插入了您的公司,然后使用生成的最后一个标识的companyId插入员工。

查看here我们可以看到,当存在重复的enities时,存在使用id的问题。在您的情况下,两家公司的id都为0,直到它们被保存为止,因此实体框架无法唯一地标识公司。