4

我知道这在 SO 上已被多次询问,但我找不到关于如何在 EF CF 中添加或更新导航属性的明确答案。

实体(简化):

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

    public class Fruit : EntityBase
        {

        }

行动结果:

 [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();
        }

然后不会向数据库提交任何更改。什么都没有发生,根本没有。有人可以指出我正确的方向吗?我已经为此奋斗了很久,谢谢...

4

1 回答 1

6

好吧,您只是附加实体(= 将状态设置为Unchanged),然后调用SaveChanges. 在这种情况下,您告诉 EF 没有任何改变-> 没有任何反应。

要更改 和 之间的关系BasketTaggedFruits您必须从数据库中加载篮子的原始水果集合,然后根据您的 Id 集合中的 Id 从篮子的已加载水果集合中删除或添加标记的水果:

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。

于 2012-04-24T16:03:10.060 回答