在EF CF中添加/更新导航属性

时间:2012-04-24 15:30:25

标签: asp.net-mvc asp.net-mvc-3 entity-framework c#-4.0 entity-framework-4.1

我知道在SO上已多次询问过这个问题,但我找不到关于如何在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();
        }

然后,不会对数据库进行任何更改。什么都没发生。有人能指出我正确的方向吗?我一直在争取这么长时间,谢谢......

1 个答案:

答案 0 :(得分:5)

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

要更改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。