(首先抱歉英语不好)
我是实体框架的新手,我做了一些测试。让我们假设我有2个对象是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();
}
我现在遇到的问题是,一旦添加了Person,就会创建一个附加地址(具有相同的值,但是新的键)。如何将现有引用添加到新对象而不是创建新对象?
答案 0 :(得分:2)
为整个操作使用一个上下文:
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或类似方法手动更改新上下文中现有地址的状态。
答案 1 :(得分:1)
首先,您是否需要在数据上下文的两个单独实例中执行此操作?我假设您这样做并且您只是提供了一个简化的示例,但如果没有,那么在整个代码中使用相同的上下文实例将解决您的问题。
但是,这是一个常见问题,尤其是在跨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();
}
答案 2 :(得分:0)
解释为什么会发生这种情况:您正在创建两个DbContexts。在第一个中,您将检索地址对象。然后,在任何Context范围之外(请参阅使用),您将创建一个新的分离的人员。它不属于您的两种情境中的任何一种。接下来发生的事情是您创建一个新的上下文并将 Person 对象添加到其中。
此上下文现在不知道您的新 Person (它是“超出范围”,或已分离),也不知道您的 Adress (它来自另一个背景)。这两个实体都将在ChangeTracker中添加并标记为已添加。
您有多种解决方案:
首先,只使用一个上下文来检索地址,创建人并添加。您需要为此更改一些代码,如果您正在处理基于服务的方案,则可能无法解决此问题。
其次,如果您无法更改此代码并且需要附加分离的对象,就像在代码段中那样,您可能希望覆盖Context类的 SaveChanges ,并遍历 ChangeTracker 中的实体。那些已经保存的(Id> 0)可以设置为“Unchanged”,或者,如果您想要保留最终进行的更改,则“已修改”。这感觉很难看,但它应该有效。