Dir*_*oms 27 entity-framework-4.1
我有一个应用程序,您可以创建一种新类型的产品,并添加一些成分.产品和成分都是保存在数据库中的实体.产品实体具有成分实体的集合.
(简化版)
public class Product
Public Sub New()
Me.Ingredients = New List(Of Ingredient)()
End Sub
Property Ingredients as ICollection(Of Ingredient)
end class
Run Code Online (Sandbox Code Playgroud)
当我第一次保存产品时,一切顺利:我只是将它添加到上下文并调用SaveChanges.
myDataContext.Products.Add(product)
myDataContext.SaveChanges()
Run Code Online (Sandbox Code Playgroud)
产品(父母)和成分(儿童)都被保存并相互链接.一切都很好.
但是,当我向现有产品添加/删除某种成分时,我开始遇到问题.我首先清除产品实体中的现有成分集合,然后再次添加更新的成分列表(我不再重复使用成分添加时刻).然后,我将产品实体的状态更改为已修改并调用savechanges.但是,在状态更改I上,获取异常" ObjectStateManager中已存在具有相同键的对象 ".
myDataContext.Entry(product).State = EntityState.Modified
Run Code Online (Sandbox Code Playgroud)
在"一些"搜索之后,我发现问题是所有成分的主键都为0(因为它们尚未添加),当您更改父实体(产品)的状态时,所有子实体(成分) )使用0的键附加到上下文,这会导致问题,因为键不再是唯一的.
我一直在寻找解决方案,但无法弄清楚如何解决这个问题.我尝试在更改状态之前将成分添加到上下文中,但随后缺少产品和成分之间的链接...如何使用新的,尚未添加的子实体更新现有父实体?
我使用Entity Framework 4.1和Code First.
希望你能帮我!
Sla*_*uma 37
我首先清除产品实体中的现有成分集合,然后再次添加更新的成分列表.
嗯,这是一种用于更新子集合的暴力攻击.EF没有任何魔法来更新子项 - 这意味着:添加新子项,删除已删除的子项,更新现有子项 - 只需将父项的状态设置为Modified
.基本上,此过程会强制您从数据库中删除旧子项并插入新子项,如下所示:
// 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();
}
Run Code Online (Sandbox Code Playgroud)
更好的方法是在内存中更新子集合而不删除数据库中的所有子节点:
// 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();
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
16727 次 |
最近记录: |