EF6 - 更新父对象列表中的子对象会导致枚举错误

时间:2016-05-10 20:16:58

标签: c# entity-framework linq

我需要更新一个对象列表,每个对象都有一个子对象列表。当我尝试将子对象添加到数据库上下文时,我收到错误说"收集被修改,枚举操作可能无法执行"。我尝试过更改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();
}

我到处寻找答案,但无法弄清楚这一点。我尝试修复它的每一种方式都会得到相同的结果。有什么想法吗?

1 个答案:

答案 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()