实体4.1使用新的子实体更新现有的父实体 [英] Entity 4.1 Updating an existing parent entity with new child Entities

查看:138
本文介绍了实体4.1使用新的子实体更新现有的父实体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个应用程序,您可以在其中创建一种新型产品,并向其中添加一些成分.产品和成分都是保存在数据库中的实体.产品实体具有成分实体的集合.

I have an application where you can create a new type of product and add to that product some ingredients. The product and the ingredients are both entities saved in a database. The product entity has a collection of ingredient entities.

(简体版)

public class Product
   Public Sub New()
     Me.Ingredients = New List(Of Ingredient)()
   End Sub

   Property Ingredients as ICollection(Of Ingredient)
end class

当我第一次保存产品时,一切顺利:我只是将其添加到上下文中,然后调用SaveChanges.

When I save the product for the first time, all goes well: I just add it to the context and call SaveChanges.

myDataContext.Products.Add(product)
myDataContext.SaveChanges()

产品(父级)和配料(子级)都被保存并相互链接.一切都很好.

Both the product (parent) and the ingredients (children) are saved and linked to each other. All is well.

但是,当我在现有产品中添加/删除成分时,我开始遇到问题.我首先清除产品实体中现有的成分集合,然后再次添加成分的更新列表(我不会在此刻重复使用成分).然后,我将产品实体的状态更改为已修改,并调用savechanges.但是,在状态更改为I时,出现异常" ObjectStateManager中已经存在具有相同键的对象".

However when I add/remove an ingredient to an existing product, I start running into problems. I first clear the existing ingredients collection in the product entity and then add the updated list of ingredients again (I don't re-use ingredients add the moment). I then change the state of the product entity to modified and call savechanges. On the state changing I, however, get the exception "An object with the same key already exists in the ObjectStateManager".

myDataContext.Entry(product).State = EntityState.Modified

在一些"搜索之后,我发现问题在于所有成分的主键均为0(因为尚未添加),并且当您更改父实体(产品)的状态时,所有子对象实体(成分)使用键0附加到上下文,这会导致问题,因为键不再唯一.

After "some" searching I figured out that the problem is that all the ingredients have a primary key of 0 (as they aren't added yet) and when you change the state of the parent entity (product), all child entities (ingredients) are attached to the context with the key of 0, which causes the problem as the keys are no longer unique.

我一直在寻找解决方案,但不知道如何解决此问题.我尝试在更改状态之前将成分添加到上下文中,但是缺少产品和成分之间的链接...如何使用新的,尚未添加的子实体更新现有的父实体?

I have been searching for a solution but can't figure out how to solve this problem. I tried adding the ingredients to the context before changing the state, but then the link between the product and ingredients is missing... How do I update an existing parent entity with new, not yet added child entities?

我使用Entity Framework 4.1和Code First.

I use Entity Framework 4.1 and Code First.

希望你能帮助我!

推荐答案

我首先要清除产品中现有的成分集合 实体,然后再次添加成分的更新列表.

I first clear the existing ingredients collection in the product entity and than add the updated list of ingredients again.

好吧,这是一种蛮力攻击来更新子级集合. EF没有任何魔术来更新子级,这意味着:仅将父级的状态设置为Modified,即可添加新的子级,删除已删除的子级,更新现有的子级.基本上,此过程会迫使您也从数据库中删除旧的子项,然后插入新的子项,如下所示:

Well, this is kind of brute-force-attack to update the child collection. EF doesn't have any magic to update the children - which means: adding new children, deleting removed children, updating existing children - by only setting the state of the parent to Modified. Basically this procedure forces you to delete the old children also from the database and insert the new one, like so:

// product is the detached product with the detached new children collection
using (var context = new MyContext())
{
    var productInDb = context.Products.Include(p => p.Ingredients)
        .Single(p => p.Id == product.Id);

    // Update scalar/complex properties of parent
    context.Entry(productInDb).CurrentValues.SetValues(product);

    foreach (var ingredient in productInDb.Ingredients.ToList())
        context.Ingredients.Remove(ingredient);

    productInDb.Ingredients.Clear(); // not necessary probably

    foreach (var ingredient in product.Ingredients)
        productInDb.Ingredients.Add(ingredient);

    context.SaveChanges();
}

更好的过程是在不删除数据库中所有子项的情况下更新内存中的子项集合:

The better procedure is to update the children collection in memory without deleting all children in the database:

// product is the detached product with the detached new children collection
using (var context = new MyContext())
{
    var productInDb = context.Products.Include(p => p.Ingredients)
        .Single(p => p.Id == product.Id);

    // Update scalar/complex properties of parent
    context.Entry(productInDb).CurrentValues.SetValues(product);

    var ingredientsInDb = productInDb.Ingredients.ToList();
    foreach (var ingredientInDb in ingredientsInDb)
    {
        // Is the ingredient still there?
        var ingredient = product.Ingredients
            .SingleOrDefault(i => i.Id == ingredientInDb.Id);

        if (ingredient != null)
            // Yes: Update scalar/complex properties of child
            context.Entry(ingredientInDb).CurrentValues.SetValues(ingredient);
        else
            // No: Delete it
            context.Ingredients.Remove(ingredientInDb);
    }

    foreach (var ingredient in product.Ingredients)
    {
        // Is the child NOT in DB?
        if (!ingredientsInDb.Any(i => i.Id == ingredient.Id))
            // Yes: Add it as a new child
            productInDb.Ingredients.Add(ingredient);
    }

    context.SaveChanges();
}

这篇关于实体4.1使用新的子实体更新现有的父实体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆