C# 实体框架4.3.1,DbContext使用现有引用对象添加对象

C# 实体框架4.3.1,DbContext使用现有引用对象添加对象,c#,.net,entity-framework-4,entity-framework-4.1,poco,C#,.net,Entity Framework 4,Entity Framework 4.1,Poco,(首先,为糟糕的英语感到抱歉) 我是实体框架的新手,我做了一些测试。假设有两个对象是POCO对象。人和地址 我的场景是,我想在DbContext中添加一个新的Person,该Person引用了一个已经存在的对象。这两个实体之间的联系是一种多对多关系 using ( var t = new Tww.SV.Models.Model.Portal.SVPortalEntities() ) { testaddress = ( from c in t.Adresses

(首先,为糟糕的英语感到抱歉)

我是实体框架的新手,我做了一些测试。假设有两个对象是POCO对象。人和地址

我的场景是,我想在DbContext中添加一个新的Person,该Person引用了一个已经存在的对象。这两个实体之间的联系是一种多对多关系

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

我现在的问题是,一旦添加了此人,就会创建一个附加的地址(具有相同的值,但有一个新的键)。如何将现有引用添加到新对象而不是创建新对象?

首先,是否需要在数据上下文的两个单独实例中执行此操作?我假设您这样做了,并且您只是提供了一个简化的示例,但是如果没有,那么在整个代码中使用相同的上下文实例将解决您的问题

然而,这是一个常见的问题,尤其是在跨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();
}
public void FixUp(EntityContext c)
{
for(int i=0;ia.Id=this.Addresses[i].Id);
if(现有!=null)
{
此。地址[i]=现有;
}
}
}
使用(var k=new EntityContext())
{
newPerson.FixUp(k);
k、 人员。添加(新人员);
k、 保存更改();
}

首先,是否需要在数据上下文的两个单独实例中执行此操作?我假设您这样做了,并且您只是提供了一个简化的示例,但是如果没有,那么在整个代码中使用相同的上下文实例将解决您的问题

然而,这是一个常见的问题,尤其是在跨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();
}
public void FixUp(EntityContext c)
{
for(int i=0;ia.Id=this.Addresses[i].Id);
if(现有!=null)
{
此。地址[i]=现有;
}
}
}
使用(var k=new EntityContext())
{
newPerson.FixUp(k);
k、 人员。添加(新人员);
k、 保存更改();
}

对整个操作使用一个上下文:

 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或类似工具在新上下文中手动更改现有地址的状态。

整个操作使用一个上下文:

 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或类似工具在新上下文中手动更改现有地址的状态。

要解释为什么会发生这种情况:您正在创建两个DBContext。在第一种方法中,检索一个adress对象。然后,在任何上下文范围之外(请参见您的使用),您正在创建一个新的分离的人。它不属于您的两个上下文中的任何一个。接下来发生的事情是创建一个新的上下文,并将Person对象添加到其中

这个上下文现在不知道你的新朋友(它是“超出范围”或分离的),也不知道你的地址(它来自另一个上下文)。这两个实体都将在ChangeTracker中添加并标记为已添加

您有多种解决方案:

  • 首先,只使用一个上下文来检索您的地址,在其中创建您的联系人并添加它。为此,您需要对代码进行一些更改,如果您使用的是基于服务的方案,则可能无法实现

  • 其次,如果您没有机会更改此代码,并且需要附加分离的对象,就像您在代码段中所做的那样,那么您可能希望覆盖上下文类的SaveChanges,并在ChangeTracker中迭代实体。那些已经保存(Id>0)的内容可以设置为“未更改”,或者,如果您希望保留最终所做的更改,可以设置为“已修改”。这感觉很难看,但应该有用


    • 要解释为什么会发生这种情况:您正在创建两个DBContext。在第一种方法中,检索一个adress对象。然后,在任何上下文范围之外(请参见您的使用),您正在创建一个新的分离的人。它不属于您的两个上下文中的任何一个。接下来发生的事情是创建一个新的上下文,并将Person对象添加到其中

      这个上下文现在不知道你的新朋友(它是“超出范围”或分离的),也不知道你的地址(它来自另一个上下文)。这两个实体都将在ChangeTracker中添加并标记为已添加

      您有多种解决方案:

      • 首先,只使用一个上下文来检索您的地址,在其中创建您的联系人并添加它。您需要为此更改代码一点,如果您正在处理基于服务的场景,则可能不会解决此问题

      • 其次,如果您没有机会更改此代码,并且需要附加分离的对象,就像您在代码段中所做的那样,那么您可能希望覆盖上下文类的SaveChanges,并在ChangeTracker中迭代实体。那些已经保存(Id>0)的内容可以设置为“未更改”,或者,如果您希望保留最终所做的更改,可以设置为“已修改”。这感觉很难看,但应该有用


      最简单的方法是覆盖保存更改,遍历所有实体和已保存的实体(Id>0),将它们设置为“未更改”,或者,如果您希望保留最终所做的更改,“修改”