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