asp.net-mvc - 在 EF CF 中添加/更新导航属性

标签 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
        {

        }

操作结果:

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

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

最佳答案

好吧,您只需附加实体(= 将状态设置为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。

关于asp.net-mvc - 在 EF CF 中添加/更新导航属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10301127/

相关文章:

c# - FirstOrDefault 两种方式

jquery - 等待操作显示图像时显示微调器

c# - EF 代码首先使用空查找表设置外键

asp.net-mvc-3 - ASP.NET Authorize属性和Admin用户角色

ASP.NET MVC SiteMap 和/或安全修整

c# - EF 代码生成 : How to get a System enum to work as an EdmEnumType?

c# - Entity Framework 中的整数列表

c# - 一些 CSS 未加载

c# - 解释 MVC 授权属性如何执行类似 AOP 的操作

asp.net-mvc-3 - 仅在modelstate错误时显示div