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

Jef*_*den 4 asp.net-mvc entity-framework c#-4.0 entity-framework-4.1 asp.net-mvc-3

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

实体(简化):

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

    public class Fruit : EntityBase
        {

        }
Run Code Online (Sandbox Code Playgroud)

的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});
    }
Run Code Online (Sandbox Code Playgroud)

我已经尝试了上面的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();
        }
Run Code Online (Sandbox Code Playgroud)

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

Sla*_*uma 5

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

要更改之间的关系Basket,TaggedFruits您必须从数据库中加载篮子的原始水果集合,然后根据您的Id集合中的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();
}
Run Code Online (Sandbox Code Playgroud)

您也可以将int[] selectedFruits集合传递给此方法,因为只需要ID.