实体框架4.3.1,DbContext添加具有现有引用对象的对象
本文关键字:对象 引用 添加 DbContext 框架 实体 | 更新日期: 2023-09-27 18:27:43
(首先抱歉英语不好)
我是实体框架的新手,我会做一些测试。假设我有两个对象是POCO对象。人员和地址。
我的场景是,我想向DbContext添加一个新的Person,它引用了一个已经存在的Object。这两个实体之间的联系是多对多的关系。
using ( var t = new Tww.SV.Models.Model.Portal.SVPortalEntities() )
{
testaddress = ( from c in t.Adresses
select c ).ToList().FirstOrDefault();
}
var newPerson = new Person();
newPerson.Name = "Henry";
newPerson.Adresses.Add( testaddress );
using ( var k = new Tww.SV.Models.Model.Portal.SVPortalEntities() )
{
k.Persons.Add(newPerson);
k.SaveChanges();
}
我现在遇到的问题是,一旦添加人员,就会创建一个额外的地址(具有相同的值,但有一个新的密钥)。如何将现有引用添加到新对象而不是创建新对象?
对整个操作使用一个上下文:
using ( var t = new Tww.SV.Models.Model.Portal.SVPortalEntities() )
{
testaddress = ( from c in t.Adresses
select c ).ToList().FirstOrDefault();
var newPerson = new Person();
newPerson.Name = "Henry";
newPerson.Adresses.Add( testaddress );
k.Persons.Add(newPerson);
k.SaveChanges();
}
如果不能做到这一点,则需要通过ObjectStateManager或类似程序手动更改新上下文中现有地址的状态。
首先,是否需要在数据上下文的两个独立实例中执行此操作?我假设您提供了一个简化的示例,但如果没有,那么在整个代码中使用相同的上下文实例将解决您的问题。
然而,这是一个常见的问题,尤其是在跨WCF等服务使用EF类时。我找到的最好的解决方案是在保存传入的新对象之前先"修复"它们。我将是第一个管理我觉得这"丑陋"的人,但我也没有找到任何更好的选择,实际上一直有效。我通常将引用重新关联代码放入实体类的另一个部分类段中的方法中:
public void FixUp(EntityContext c)
{
for (int i = 0; i < this.Addresses.Count; i++)
{
var existing = c.Addresses.SingleOrDefault(a => a.Id = this.Addresses[i].Id);
if (existing != null)
{
this.Addresses[i] = existing;
}
}
}
using (var k = new EntityContext())
{
newPerson.FixUp(k);
k.Persons.Add(newPerson);
k.SaveChanges();
}
要解释为什么会发生这种情况:您正在创建两个DbContext。在第一个步骤中,检索一个地址对象。然后,在任何上下文范围之外(使用查看),您正在创建一个新的分离的人员。它不属于你的两个上下文中的任何一个。接下来要做的是创建一个新的上下文,并将Person对象添加到其中
此上下文现在不知道您的新人员(它"超出范围",或分离),也不知道您地址。(它来自另一个上下文)。这两个实体都将在ChangeTracker中添加并标记为这样,added。
您有多种解决方案:
-
首先,只使用一个上下文来检索Adress,在中创建Person并添加。您需要为此更改一些代码,如果您在基于服务的场景中工作,这可能不适合您。
-
其次,如果您没有机会更改此代码,并且需要附加分离的对象,就像您在代码片段中所做的那样,您可能需要覆盖Context类的SaveChanges,并在ChangeTracker中的实体中迭代。那些已经保存的(Id>0)可以设置为"未更改",或者,如果您希望保留最终所做的更改,则可以设置"已修改"。这感觉很难看,但应该行得通。