4

我知道在此處多次提到過這個問題,但我無法找到如何在EF CF中添加或更新導航屬性的確定答案。在EF中添加/更新導航屬性CF

實體(簡體):

public class Basket : EntityBase 
    { 
     public virtual List<Fruit> TaggedFruits { get; set; } 
    } 

    public class Fruit : EntityBase 
     { 

     } 

的ActionResult:

[HttpPost] 
     public ActionResult SaveTags(Basket basket, int[] selectedFruits) 
     { 
     basket.TaggedFruits = new List<Fruits>(); 

     foreach (int guid in selectedFruits) 
      basket.TaggedFruits.Add(repository.Fruits.FirstOrDefault(p => p.Id == guid)); 

     using (var context = new EFDbContext()) 
     { 
      context.Baskets.Attach(basket); 
      context.SaveChanges(); 
     } 

     return RedirectToAction("GetBasket", new {guid = basket.Guid}); 
    } 

我已經試過SaveTags方法多次重複以上,但從來沒有得到它的工作。這一個拋出:

一個實體對象不能被多個IEntityChangeTracker實例引用。

在研究了這裏和其他網站之後,這個錯誤明顯地說明,在方法中混合我的存儲庫模式和DBContext會導致衝突。

如果我移動標籤到存儲庫,用下面的方法:

[HttpPost] 
      public ActionResult SaveTags(Basket basket, int[] selectedFruits) 
      { 
        List<Fruit> taggedFruits = new List<Fruit>(); 
      foreach (int guid in selectedFruits) 
       taggedFruits.Add(new Fruit {Id = guid}); 

      libraryRepository.TagBasket(basket, taggedFruits); 

      return RedirectToAction("GetBasket", new {guid = basket.Guid}); 
     } 



/*in repository*/ 
    public void TagBasket(Basket basket, List<Fruit> fruits) 
      { 
       basket.Taggedfruits = new List<Fruit>(); 
       foreach (var fruit in fruits) 
       { 
        basket.Taggedfruits.Add(Fruit); 
       } 


      context.Baskets.Attach(basket); 
     context.SaveChanges(); 
     } 

然後沒有改變被提交到數據庫。根本沒有任何反應。有人能指引我朝着正確的方向嗎?我一直在爭取這種方式,長,謝謝...

回答

5

那麼,你只附加實體(=設置狀態Unchanged),然後致電SaveChanges。在這種情況下,你告訴EF沒有任何改變 - >沒有任何反應。

要更改BasketTaggedFruits之間的關係必須從數據庫中加載籃原水果集合,然後刪除或根據IDS的標記水果添加自/至裝載的水果收集籃的你標識集合:

public void TagBasket(Basket basket, List<Fruit> fruits) 
{ 
    var basketInDB = context.Baskets.Include(b => b.Taggedfruits) 
     .Single(b => b.Id == basket.Id); 

    foreach (var fruitInDB in basketInDB.Taggedfruits.ToList()) 
     if (!fruits.Any(f => f.Id == fruitInDB.Id)) 
      basketInDB.Taggedfruits.Remove(fruitInDB); 

    foreach (var fruit in fruits) 
     if (!basketInDB.Taggedfruits.Any(f => f.Id == fruit.Id)) 
     { 
      var newFruit = new Fruit { Id = fruit.Id }; 
      context.Fruits.Attach(newFruit); 
      basketInDB.TaggedFruits.Add(newFruit); 
     } 

    // Next line is only necessary if other properties in basket 
    // could have been changed in your view 
    context.Entry(basketInDB).CurrentValues.SetValues(basket); 

    context.SaveChanges(); 
} 

你也可以通過int[] selectedFruits收集到這種方法,因爲只需要的ID。

+0

我可以吻你。謝謝。只有我更改的行是: context.Entry(basketInDB).CurrentValues.SetValues(basket); 我將它設置爲 context.Entry(basketInDB).CurrentValues.SetValues(basketInDB); ,因爲我失去了傳遞給方法的籃子對象中的數據。這有什麼問題嗎?它似乎堅持了我打算保留的所有舊數據,但仍然更新了這種關係。好酷? – 2012-04-24 16:36:07

+0

@JeffBorden:不,這沒有問題,但它使得這條線是多餘的(你正在更新一個本身的實體=根本沒有更新)。只需完全刪除該行,它僅適用於籃子上的其他標量屬性,並不會影響更新與TaggedFruits的關係。 – Slauma 2012-04-24 16:42:35

+0

明白了。救生員,謝謝你的隊友。 – 2012-04-24 16:48:35