2012-11-05 69 views
45

我目前正在使用實體框架的最新版本的項目,我遇到了一個問題,我似乎無法解決。實體框架,更新相關對象的問題

當涉及到更新現有對象時,我可以很容易地更新對象屬性,直到涉及到對另一個類的引用的屬性。

在下面的例子中,我有一個叫做Foo類,其存儲各種性質,與其它類

public class Foo 
{ 
    public int Id {get; set;} 
    public string Name {get; set;} 
    public SubFoo SubFoo {get; set} 
    public AnotherSubFoo AnotherSubFoo {get; set} 
} 

的這些是實例2當我使用下面編輯方法,我通過在對象我希望更新,我可以設法讓名稱正確更新,但是我還沒有設法找到一種方法來獲得SubFoo的屬性改變。例如,如果SubFoo類具有Name屬性,並且已更改,並且在我的數據庫和newFoo之間不同,它不會更新。

public Foo Edit(Foo newFoo) 
{ 

     var dbFoo = context.Foo 
          .Include(x => x.SubFoo) 
          .Include(x => x.AnotherSubFoo) 
          .Single(c => c.Id == newFoo.Id); 



     var entry = context.Entry<Foo>(dbFoo); 
     entry.OriginalValues.SetValues(dbFoo); 
     entry.CurrentValues.SetValues(newFoo); 

     context.SaveChanges(); 

     return newFoo; 
} 

任何幫助或指針將不勝感激。

UPDATE: 基於由Slauma評論我已經修改了我的方法

public Foo Edit(Foo newFoo) 
{ 

     var dbFoo = context.Foo 
          .Include(x => x.SubFoo) 
          .Include(x => x.AnotherSubFoo) 
          .Single(c => c.Id == newFoo.Id); 



     context.Entry(dbFoo).CurrentValues.SetValues(newFoo); 
     context.Entry(dbFoo.SubFoo).CurrentValues.SetValues(newFoo.SubFoo); 

     context.SaveChanges(); 

     return newFoo; 
} 

現在,當運行這個,我得到的錯誤

的實體類型Collection`1不是一部分的模型爲當前的 上下文。

爲了避免這個搞定了,我添加了代碼以嘗試將newFoo子類附加到上下文,但通過一個錯誤,指出該的ObjectManager已經有了一個實體相同

對象在ObjectStateManager中已經存在相同的密鑰。 的ObjectStateManager不能用相同的 關鍵

回答

77

CurrentValues.SetValues只更新標量的屬性,但沒有相關的實體跟蹤多個目標,所以你必須爲每個相關實體做相同的:

public Foo Edit(Foo newFoo) 
{ 
    var dbFoo = context.Foo 
         .Include(x => x.SubFoo) 
         .Include(x => x.AnotherSubFoo) 
         .Single(c => c.Id == newFoo.Id); 

    context.Entry(dbFoo).CurrentValues.SetValues(newFoo); 
    context.Entry(dbFoo.SubFoo).CurrentValues.SetValues(newFoo.SubFoo); 
    context.Entry(dbFoo.AnotherSubFoo).CurrentValues.SetValues(newFoo.AnotherSubFoo); 

    context.SaveChanges(); 

    return newFoo; 
} 

如果關係可能已被完全刪除或已創建您還需要明確處理這些情況:

public Foo Edit(Foo newFoo) 
{ 
    var dbFoo = context.Foo 
         .Include(x => x.SubFoo) 
         .Include(x => x.AnotherSubFoo) 
         .Single(c => c.Id == newFoo.Id); 

    context.Entry(dbFoo).CurrentValues.SetValues(newFoo); 
    if (dbFoo.SubFoo != null) 
    { 
     if (newFoo.SubFoo != null) 
     { 
      if (dbFoo.SubFoo.Id == newFoo.SubFoo.Id) 
       // no relationship change, only scalar prop. 
       context.Entry(dbFoo.SubFoo).CurrentValues.SetValues(newFoo.SubFoo); 
      else 
      { 
       // Relationship change 
       // Attach assumes that newFoo.SubFoo is an existing entity 
       context.SubFoos.Attach(newFoo.SubFoo); 
       dbFoo.SubFoo = newFoo.SubFoo; 
      } 
     } 
     else // relationship has been removed 
      dbFoo.SubFoo = null; 
    } 
    else 
    { 
     if (newFoo.SubFoo != null) // relationship has been added 
     { 
      // Attach assumes that newFoo.SubFoo is an existing entity 
      context.SubFoos.Attach(newFoo.SubFoo); 
      dbFoo.SubFoo = newFoo.SubFoo; 
     } 
     // else -> old and new SubFoo is null -> nothing to do 
    } 

    // the same logic for AnotherSubFoo ... 

    context.SaveChanges(); 

    return newFoo; 
} 

如果關係已經改變了標量屬性,您最終還需要將附加實體的狀態設置爲Modified

編輯

如果 - 根據您的評論 - Foo.SubFoo實際上是一個集合而不是隻是一個參考,你需要這樣的更新相關實體:

public Foo Edit(Foo newFoo) 
{ 
    var dbFoo = context.Foo 
         .Include(x => x.SubFoo) 
         .Include(x => x.AnotherSubFoo) 
         .Single(c => c.Id == newFoo.Id); 

    // Update foo (works only for scalar properties) 
    context.Entry(dbFoo).CurrentValues.SetValues(newFoo); 

    // Delete subFoos from database that are not in the newFoo.SubFoo collection 
    foreach (var dbSubFoo in dbFoo.SubFoo.ToList()) 
     if (!newFoo.SubFoo.Any(s => s.Id == dbSubFoo.Id)) 
      context.SubFoos.Remove(dbSubFoo); 

    foreach (var newSubFoo in newFoo.SubFoo) 
    { 
     var dbSubFoo = dbFoo.SubFoo.SingleOrDefault(s => s.Id == newSubFoo.Id); 
     if (dbSubFoo != null) 
      // Update subFoos that are in the newFoo.SubFoo collection 
      context.Entry(dbSubFoo).CurrentValues.SetValues(newSubFoo); 
     else 
      // Insert subFoos into the database that are not 
      // in the dbFoo.subFoo collection 
      dbFoo.SubFoo.Add(newSubFoo); 
    } 

    // and the same for AnotherSubFoo... 

    db.SaveChanges(); 

    return newFoo; 
} 
+0

感謝您的評論,我已經發布了一個更新我的問題 – Thewads

+0

@Thewads:我只能想象,你得到這個「*集合......是不是模型的一部分... *「錯誤,當'Foo.SubFoo'是一個*集合*類型。但它只是一個引用'公衆SubFoo SubFoo {get;在示例模型中設置},而不是集合。它真的沒有收藏?我的回答是基於你當前的模型,其中'SubFoo'不是一個集合。 – Slauma

+0

對不起,我沒有意識到有收藏的模型會有所作爲......我的錯誤。在我處理的模型中:public ICollection SubFoo {get;設置;} – Thewads

0

您也可以致電錶獨立

MyContext db = new MyContext 
// I like using asynchronous calls in my API methods 
var OldFoo = await db.Foo.FindAsync(id); 
var OldAssociateFoo = db.AssociatedFoo; 
var NewFoo = OldFoo; 
var NewAssociatedFoo = OldAssociatedFoo; 

NewFoo.SomeValue = "The Value"; 
NewAssociatedFoo.OtherValue = 20; 

db.Entry(OldFoo).CurrentValues.SetValues(NewFoo); 
db.Entry(OldAssociatedFoo).CurrentValues.SetValues(NewAssociatedFoo); 

await db.SaveChangesAsync();