2012-12-03 53 views
2

正如您從下面的代碼中可以看到的,我使用AsNoTracking來獲取我的對象。 我那麼即使使用ObjectSateManager看看是怎麼回事,我可以看到 沒有在L *藏品被跟蹤,但我仍然得到AsNoTracking和ObjectStateManager的實體框架錯誤

「具有相同鍵的對象已經存在於ObjectStateManager該ObjectStateManager不能使用相同的鍵追蹤多個對象「。

任何想法?

==========================================
BasketRepository回購= new BasketRepository();

  var ba = repo.GetById(8); 

      var bpro = new BasketProduct(ba, ba.BasketProducts.First().Product, 3); 

      repo.AddToBasket(bpro); 
      repo.Save(); 

==================================

public Basket GetById(int basketId) 
    { 
     // eager-load product info 
     var basket = dbContext.Baskets.Include("BasketProducts") 
             .Include("BasketProducts.Product.Brand").AsNoTracking().SingleOrDefault(b => b.BasketId == basketId);; 
     return basket; 
    } 

== ====================================

public void AddToBasket(BasketProduct product) 
    { 
     var ctx = ((IObjectContextAdapter)dbContext).ObjectContext; 
     ObjectStateManager objectStateManager = ctx.ObjectStateManager; 
     var l1 = objectStateManager.GetObjectStateEntries(EntityState.Added); 
     var l2 = objectStateManager.GetObjectStateEntries(EntityState.Modified); 
     var l3 = objectStateManager.GetObjectStateEntries(EntityState.Deleted); 
     //var l4 = objectStateManager.GetObjectStateEntries(EntityState.Detached); 
     var l5 = objectStateManager.GetObjectStateEntries(EntityState.Unchanged); 

     var existingProductInBasket = dbContext.BasketProducts.AsNoTracking().SingleOrDefault(b => b.BasketId == product.BasketId && b.ProductId == product.ProductId); 
     var l6 = objectStateManager.GetObjectStateEntries(EntityState.Added); 
     var l7 = objectStateManager.GetObjectStateEntries(EntityState.Modified); 
     var l8 = objectStateManager.GetObjectStateEntries(EntityState.Deleted); 
     //var l4 = objectStateManager.GetObjectStateEntries(EntityState.Detached); 
     var l9 = objectStateManager.GetObjectStateEntries(EntityState.Unchanged); 

     //objectStateManager. 
     dbContext.Entry<BasketProduct>(product).State = existingProductInBasket == null ? EntityState.Added : EntityState.Modified; 

    } 
+0

問題是:dbContext的壽命是多少?當你改變對象的狀態時它總是新的嗎? –

回答

0

這實際上是壞的。從概念上來說,熟悉如何使用EF追蹤和跟蹤事物 的想法可能有點困難。祕密是要記住,只要圖形的對象與狀態X相關聯,那麼如果您有一個對象(對象與其他對象有關係),則圖形中的所有其他對象似乎也被附加在該狀態中。

在我的情況我很愚蠢地使用 VAR BPRO =新BasketProduct(BA,ba.BasketProducts.First()產品,3); 創建一個實際上已經存在於數據庫中的測試產品,它是包含購物籃及其產品的對象圖的一部分。當我試圖附上這個「新」籃子時,EF正確地抱怨在附圖中已經存在具有相同密鑰的對象!

1

當您使用asNoTracking()時,您會得到一個無法正常更新EntityState.Modified的未連接實體。然後,一個技巧是用非緩存的實體值替換緩存的實體值。

這裏是我用於特殊情況的源代碼,其中asNoTracking是必要的。它可以是

private T ReplaceEntity(T cachedEntity, T nonCachedEntity) { 

    dbContext.Entry(cachedEntity).CurrentValues.SetValues(nonCachedEntity); 

    return cachedEntity; 
} 

一個常見的用途可以是:

public virtual T FindFirstBy(System.Linq.Expressions.Expression<Func<T, bool>> predicate, bool asNoTracking = false) 
{ 
    if (asNoTracking) 
    { 
      T cachedEntity = dbContext.Set<T>().FirstOrDefault(predicate); 
      T nonCachedEntity = dbContext.Set<T>().AsNoTracking().FirstOrDefault(predicate); 

      return ReplaceEntity(cachedEntity, nonCachedEntity); 
    } 
    return dbContext.Set<T>().FirstOrDefault(predicate); 
} 

您的具體情況:

var cachedEntity = dbContext.BasketProducts.SingleOrDefault(b => b.BasketId == product.BasketId && b.ProductId == product.ProductId); 
var nonCachedEntity = dbContext.BasketProducts.AsNoTracking().SingleOrDefault(b => b.BasketId == product.BasketId && b.ProductId == product.ProductId); 

var product= ReplaceEntity(cachedEntity, nonCachedEntity); 
dbContext.Entry<BasketProduct>(product).State = EntityState.Modified; 

希望它可以幫助!