添加相关实体在不使用导航属性 [英] Adding Related Entities without using navigation properties

查看:134
本文介绍了添加相关实体在不使用导航属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下类,用于测试设置:

 公共类公司
{
[ DatabaseGenerated(DatabaseGeneratedOption.Identity)
公众诠释标识{搞定;组; }
公共字符串名称{;组; }
}

公共类员工
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)
公众诠释标识{搞定;组; }

公共字符串名称{;组; }

公众诠释CompanyId {搞定;组; }
公共虚拟公司公司{搞定;组; }
}

公共类EFTestDbContext:的DbContext
{
公共DbSet<员工>员工{搞定;组; }
公共DbSet<公司+ GT;公司{搞定;组; }
}

有关测试的缘故,我想插入一个公司,一个员工该公司单一的SaveChanges称,像这样的:

 公司公司=新公司
{
名称=样本公司
};

context.Companies.Add(公司);

// **取消注释测试2
//公司Company2的=新公司
// {
//名称=一些其他公司的
//};
//context.Companies.Add(company2);

员工员工=新员工
{
NAME =汉斯,
CompanyId = company.Id
};
context.Employees.Add(员工);

context.SaveChanges();



虽然我不使用导航性能,而是我做了相关ID,则不知何故神不知鬼不觉的工作 - 雇员被保存适当的外键的公司,得到了从0更新到真正的价值,这让我走?!?!一些隐藏的C#功能?



然后,我已经决定要添加更多的代码,这是在片段评论上面,使得它被插入2个公司实体和1点¯xEmployee实体,然后我得到异常:




无法确定CodeLab.EFTest.Employee_Company关系的主要终点。多补充实体可能具有相同的主键。




这是否意味着在国外关键是0,和案件有单匹配实体被插在同一个调用SaveChanges交易,实体框架将假设外键应该是针对匹配实体?



在第二次测试的时候,有两个实体匹配的关系类型,实体框架,因为它是不能够弄明白该公司员工的应与抛出一个异常



编辑:



我已经做了第二次检查,并注释掉一行。首先测试仍然运行正常(因为对于int默认值为0):

 员工员工=新员工
{
产品名称=汉斯,
// CompanyId = company.Id // *不需要这在所有
};


解决方案

你不是真的打一个隐藏的C#的功能,也许一个不起眼的实体框架功能。



在指定 CompanyId ,EF知道,具有公司 ID = 0 (在那一刻)是员工的父母。在许多场合, EF执行时 DetectChanges ,这也执行关系修正的:匹配的外键值和参考。这发生在你执行



  context.Employees.Add(员工); 

现在EF将使用参考,而不是外键值,因此它知道它的FK值存储在数据库中。



当您创建两个企业中,有具有相同的瞬态键值两个实例,因此EF不能再进行选择。



所以,当你想存储它总是建议将在FK值代替引用新的连接的对象。


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:

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 ?!?! Some hidden C# feature?

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:

Unable to determine the principal end of the 'CodeLab.EFTest.Employee_Company' relationship. 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?

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):

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.

When you assign the CompanyId, EF knows that the the company having Id = 0 (at that moment) is the employee's parent. On numerous occasions, EF executes DetectChanges, which also executes relationship fixup: matching foreign key values and references. 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.

When you create two companies, there are two instances having the same transient key value, so EF can't choose anymore.

So when you want to store new connected objects it's always recommended to set references in stead of FK values.

这篇关于添加相关实体在不使用导航属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆