【问题标题】:Adding/updating navigation properties in EF CF在 EF CF 中添加/更新导航属性
【发布时间】:2012-05-05 06:42:36
【问题描述】:

我知道在 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 实例引用。

在研究here和其他站点后,错误显然表明将我的存储库模式与方法中的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();
        }

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

【问题讨论】:

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


    【解决方案1】:

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

    【讨论】:

    • 我可以吻你。谢谢。我更改的唯一行是: context.Entry(basketInDB).CurrentValues.SetValues(basket);我将其设置为 context.Entry(basketInDB).CurrentValues.SetValues(basketInDB);因为我丢失了不在传递给方法的篮子对象中的数据。这有什么问题吗?它似乎保留了我想要保留的所有旧数据,但仍然更新了关系。这么酷?
    • @JeffBorden:不,这没有问题,但是它使该行变得多余(您正在使用自身更新实体=根本没有更新)。只需完全删除该行,它仅适用于篮子上的其他标量属性,不影响更新到 TaggedFruits 的关系。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-03
    • 1970-01-01
    • 2021-11-10
    • 1970-01-01
    • 2016-12-21
    相关资源
    最近更新 更多