我需要更新一个对象列表,每个对象都有一个子对象列表。当我尝试将子对象添加到数据库上下文时,我收到错误说"收集被修改,枚举操作可能无法执行"。我尝试过更改ToList(),这没有用。这是一个示例:
public void Update(List<Parent> parents)
{
// I've made this a FOR loop instead of FOREACH - doesn't help
for (int i = 0; i < parents.Count; i++)
{
var parent = parents[i];
var dbEntry = _db.Entry(parent);
dbEntry.State = EntityState.Modified;
foreach (var child in dbEntry.Entity.Children)
if (!parent.Children.Exists(ent => ent.Id == child.Id))
_db.Children.Remove(child);
foreach (var child in parent.Children)
if (child.Id == 0)
dbEntry.Entity.Children.Add(child); <-- ENUMERATION ERROR HERE
}
context.SaveChanges();
}
我到处寻找答案,但无法弄清楚这一点。我尝试修复它的每一种方式都会得到相同的结果。有什么想法吗?
答案 0 :(得分:1)
从它的外观来看,你试图将孩子们添加到你在最后一个foreach中迭代的完全相同的集合中。
var dbEntry = _db.Entry(parent);
因此
parent = dbEntry.Entity
问题在于这个foreach
foreach (var child in parent.Children)
if (child.Id == 0)
dbEntry.Entity.Children.Add(child); <--dbEntry.Entity points to same variable as parent.
在上面的foreach
parent.Children == dbEntry.Entity.Children
如果您启用了更改跟踪并且Parent.Children
属性已正确映射,则您无需执行任何操作。
如果您禁用了自动更改跟踪,那么您应该做的就是:
var dbEntry = _db.Entry(parent);
dbEntry.State = EntityState.Modified;
可能,您可能需要遍历每个孩子并将其标记为已添加,例如:
foreach (var child in parent.Children)
if (child.Id == 0) // This is a new Child
_db.Entry(child).State = EntityState.Added
以下if
声明始终为假!
foreach (var child in dbEntry.Entity.Children)
if (!parent.Children.Exists(ent => ent.Id == child.Id))
如果您要删除已从列表中删除的子项,但您知道您确实在没有AsNoTracking()
的情况下请求了这些子项。然后,您应该能够使用_db.Children.Local
属性,因为它将包含您已检索的所有实体。但请确保您检查孩子是否存在List<Parents>
中的任何一个,否则您可能会尝试删除已转换父母的孩子,例如已被采纳。
你能告诉我你为什么要手动管理这个状态?
为什么不让EF跟踪状态变化?那么除了在其他地方添加/删除实际的孩子之外,你不需要担心什么,然后只需要调用_db.SaveChanges()