2013-03-12 35 views
1

我將以下面的方式介紹這個問題:我知道互聯網上有一百萬個關於舊的「ObjectStateManager中已存在具有相同關鍵的對象」的帖子。我想,我的情況有點複雜。EF 5.0更新已經被跟蹤的實體

我有一個UnitOfWork類,它創建一個DbContext並將它傳遞給任何被調用的倉庫。我使用的模式嚴格遵循ASP.NET網站上的工作單元教程。與本教程不同,我的存儲庫採用業務實體,將它們映射到數據實體,並執行一些CRUD操作。我的業務邏輯僅適用於商業實體。這是我想要的樣本業務經理類的事:

_unitOfWork.Repository.Add(entity); 
_unitOfWork.Save(); // context.SaveChanges() under the hood 

...Perform some operations on the model... 

_unitOfWork.Repository.Update(entity); 
_unitOfWork.Save(); 

這裏是從資源庫中的樣本更新方法:

public virtual void Update(entity) 
{ 
    var dataEntity = // map from business entity to data; 

    _context.Entry(dataEntity).State = EntityState.Modified; 
} 

它在最後一行明顯失敗。這裏是我的困惑集:

  • 實體的國家的獨立
  • 當我嘗試將狀態改變修改或不變的,它給我的ObjectStateManager例外以上。我試圖從上下文(((IObjectContextAdapter)_context).ObjectContext.Detach(entity);)中分離實體時,我得到一個關於實體如何不附加到上下文的異常,因此它不能分離它。非常容易混淆(當然,我錯過了一些基本的東西)。
  • 許多其他帖子提示我進行數據庫調用,更新存儲庫中的實體,然後_unitOfWork.Save()。我不喜歡這種方法。我不需要進行不必要的網絡調用來更新實體。

存儲庫中的Update方法需要處理兩種情況:1)更新當前未被上下文跟蹤的實體; 2)更新當前由上下文跟蹤的實體。第二部分是我正在努力的。

讚賞任何幫助或見解。

謝謝!

回答

0

我發現這似乎工作的混合解決方案:

public virtual void Update(TB entity) 
     { 
      var dataEntity = Mapper.Map<TB, TD>(entity); 

      var pkey = _dbSet.Create().GetType().GetProperty("Id").GetValue(dataEntity); 
      var entry = _context.Entry(dataEntity); 

      if (entry.State == EntityState.Detached) 
      { 
       var attachedEntity = _dbSet.Find(pkey); 

       if (attachedEntity != null) 
       { 
        var attachedEntry = _context.Entry(attachedEntity); 
        attachedEntry.CurrentValues.SetValues(dataEntity); 
       } 
       else 
       { 
        entry.State = EntityState.Modified; 
       } 
      } 
      else 
      { 
       entry.State = EntityState.Modified; 
      } 
     } 
1

這意味着已經有附加到上下文具有相同的鍵作爲新dataEntity的對象。現有對象和新實體都表示數據庫中的相同條目,但它們是兩個不同的對象。

這可能表明您的_context的使用壽命過長,但很難從您的代碼判斷。可以肯定的是,上下文之前用於從數據庫中獲取一個實體,隨後被var dataEntity = ...複製。

您可能不得不縮短上下文的壽命,我不能說。如果您認爲沒關係,您可能需要使用Local集合來檢查實體是否已經存在。這樣可以節省Find仍可能產生的數據庫往返行程。

相關問題