简体   繁体   English

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

[英]Adding Related Entities without using navigation properties

I have the following classes, set for testing: 我有以下类,设置为测试:

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; }
}

For the sake of testing, I wanted to insert one company and one employee for that company with single SaveChanges call, like this: 为了测试,我想通过单个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();

Even though I am not using navigational properties, but instead I've made relation over Id, this somehow mysteriously worked - employee was saved with proper foreign key to company which got updated from 0 to real value, which made me go ?!?! 虽然我没有使用导航属性,但是我已经与Id建立了关系,这在某种程度上是神秘的 - 员工用适当的外键保存到公司,从0更新到实际价值,这让我走了?!?! Some hidden C# feature? 一些隐藏的C#功能?

Then I've decided to add more code, which is commented in the snippet above, making it to be inserting of 2 x Company entity and 1 x Employee entity, and then I got exception: 然后我决定添加更多代码,在上面的代码段中注释,使其插入2 x Company实体和1 x Employee实体,然后我得到异常:

Unable to determine the principal end of the 'CodeLab.EFTest.Employee_Company' relationship. 无法确定“CodeLab.EFTest.Employee_Company”关系的主要结尾。 Multiple added entities may have the same primary key. 多个添加的实体可以具有相同的主键。

Does this mean that in cases where foreign key is 0, and there is a single matching entity being inserted in same SaveChanges transaction, Entity Framework will assume that foreign key should be for that matching entity? 这是否意味着在外键为0并且在同一个SaveChanges事务中插入单个匹配实体的情况下,实体框架将假定外键应该用于该匹配实体?

In second test, when there are two entities matching the relation type, Entity Framework throws an exception as it is not able to figure out to which of the Companies Employee should be related to. 在第二个测试中,当有两个实体匹配关系类型时,实体框架会抛出异常,因为它无法确定应该与哪个公司员工相关联。

EDIT: 编辑:

I've done one more test, and commented out one line. 我做了一个测试,并注释掉了一行。 First test still runs properly (since default value for int is 0): 第一个测试仍然正常运行(因为int的默认值为0):

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

You're not really hitting a hidden C# feature, maybe an obscure Entity Framework feature. 你并没有真正触及隐藏的C#功能,可能是一个不起眼的实体框架功能。

When you assign the CompanyId , EF knows that the the company having Id = 0 (at that moment) is the employee's parent. 当您分配CompanyId ,EF知道Id = 0 (当时)的公司是员工的父母。 On numerous occasions, EF executes DetectChanges , which also executes relationship fixup : matching foreign key values and references. 在许多情况下, EF执行DetectChanges ,它还执行关系 DetectChanges :匹配外键值和引用。 This happens when you execute 执行时会发生这种情况

context.Employees.Add(employee);

Now EF will use the reference, rather than the foreign key value, so it knows which FK value to store in the database. 现在EF将使用引用而不是外键值,因此它知道要在数据库中存储哪个FK值。

When you create two companies, there are two instances having the same transient key value, so EF can't choose anymore. 当您创建两个公司时,有两个实例具有相同的临时键值,因此EF不能再选择。

So when you want to store new connected objects it's always recommended to set references in stead of FK values. 因此,当您想要存储新的连接对象时,始终建议设置引用而不是FK值。

You added the company to the companies table. 您将公司添加到公司表中。

context.Companies.Add(company);

Then you set the companyId of the employee: 然后设置员工的companyId:

CompanyId = company.Id

This is all that is needed to create the relationship in sql. 这是在sql中创建关系所需的全部内容。 Likely the entity framework inserted your company, then inserted the employee with a companyId of the last identity generated. 可能实体框架插入了您的公司,然后使用生成的最后一个标识的companyId插入员工。

Looking here we can see there are issues using id when there are duplicate enities. 在这里我们可以看到当存在重复的enities时使用id存在问题。 In your case both companies have an id of 0 until they are saved so entity framework can't uniquely identify a company. 在您的情况下,两个公司的id都为0,直到它们被保存为止,因此实体框架无法唯一地标识公司。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 添加查找实体而无需手动添加到相关实体的导航属性 - Adding a lookup entity without manually adding to related entities navigation properties EF 核心 3.1:在使用急切加载加载相关实体时,我应该初始化列表导航属性吗? - EF core 3.1: should I initialize list navigation properties when using eager loading to load related entities? 使用导航属性“添加”相关项是否缓慢? - Is using navigation properties to “Add” related items slow? 将相关实体添加到实体 - Adding related entities to entity Linq到实体的导航属性 - Linq to entities navigation properties 导航属性和查找实体 - Navigation Properties and Lookup Entities 使用导航属性加载实体 AsNoTracking(),无需指定包含 - Load Entities AsNoTracking() with navigation properties, without specifying includes Automapper可以使用实体的导航属性从相关实体中提取值 - Can Automapper use an entity's navigation properties to pull values from related entities 使用Web Api和EF中的Linq访问具有导航属性的实体 - Accessing entities with navigation properties using Linq in Web Api and EF 子实体的继承和导航属性 - Inheritance and navigation properties to child entities
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM