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

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

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 Employees { get; set; } public DbSet 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#function?

然后我决定添加更多代码,在上面的代码片段中注释,使其插入2 x Company实体和1 x Employee实体,然后我得到exception:

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

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

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

编辑:

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

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

你并没有真正触及隐藏的C#function,可能是一个模糊的entity frameworkfunction。

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

 context.Employees.Add(employee); 

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

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

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

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

 context.Companies.Add(company); 

然后设置员工的companyId:

 CompanyId = company.Id 

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

在这里我们可以看到当存在重复的enities时使用id存在问题。 在您的情况下,两个公司的id都为0,直到它们被保存为止,因此entity framework无法唯一地标识公司。