`收藏被修改;读取数据时,枚举操作可能不会执行错误

时间:2016-01-16 03:19:57

标签: c# entity-framework entity-framework-6

我们有一个Web应用程序,它使用Entity框架来访问数据(db是Oracle)。我们最近搬到了EF6。 我们以下列方式使用交易:

  1. 我们创建了事务,因此我们现在有EntityTransaction个对象和EntityConnection对象。
  2. 对DB进行了几次并发请求。每个请求都在自己的线程中运行(实际上请求来自客户端)。对于每个请求,使用相同的ObjectContext对象创建自己的EntityConnection。事务请求部分并行运行,因此在给定的时刻,并行运行请求很少。
  3. 在这些情况下,奇怪的错误开始发生: 例外 - Collection was modified; enumeration operation may not execute

    在读取或更新数据时,甚至在访问EntityTransaction的Connection属性时都会发生这种情况。

    堆栈跟踪的开始可能会有所不同,但结尾总是相同的:

      

    System.InvalidOperationException:修改了集合;枚举操作可能无法执行。       在System.Collections.Generic.List 1.Enumerator.MoveNextRare() at System.Linq.Enumerable.WhereSelectListIterator 2.MoveNext()       在System.Linq.Enumerable.d__14 2.MoveNext() at System.Linq.Enumerable.<DistinctIterator>d__81 1.MoveNext()       在System.Linq.Enumerable.WhereEnumerableIterator 1.MoveNext() at System.Collections.Generic.List 1..ctor(IEnumerable 1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable 1 source)       在System.Data.Entity.Infrastructure.Interception.DbInterceptionContext..ctor(IEnumerable`1 copyFrom)       在System.Data.Entity.Core.EntityClient.EntityTransaction.get_InterceptionContext()

    实际上堆栈跟踪结束还有另一种变体(但是你可以看到它们基本相同):

      

    System.InvalidOperationException:修改了集合;枚举操作可能无法执行。        在System.Collections.Generic.List 1.Enumerator.MoveNextRare() at System.Linq.Enumerable.WhereSelectListIterator 2.MoveNext()        在System.Linq.Enumerable.Any [TSource](IEnumerable 1 source, Func 2谓词)        在System.Data.Entity.Infrastructure.Interception.DbInterceptionContext..ctor(IEnumerable`1 copyFrom)        在System.Data.Entity.Core.EntityClient.EntityConnection.get_InterceptionContext()

    正如我们所看到的,错误发生在DbInterceptionContext构造函数中。 它是一种EF内部结构,并且该集合(已修改)是一个内部集合,并且没有直接链接到我们的自定义代码。

    很少注意到:

    • 我们在更新EF6之前没有出现此类错误。
    • 对于大约1%的交易,错误发生的情况相对较少。

    出现此错误的原因是什么?这是EF6的问题吗? 或者我们以错误的方式使用EF? 是否允许为一个应该同时运行的连接创建多个ObjectContext - ?

    如果需要,我可以提供完整调用堆栈的一些示例。

1 个答案:

答案 0 :(得分:2)

如果在迭代时对集合添加/删除,则会出现此问题:

// throws "collection was modified" error
foreach (var item in myCollection) {
    myCollection.Remove(item);
}

// to fix this problem, iterate over a copy of the collection whose count does not change
var fixedSize = myCollection.ToArray();
foreach (var item in fixedSize) {
    myCollection.Remove(item);
}

也许您的旧代码返回数组,而EF 6代码返回IEnumerable?您应该检查您的创建/更新/删除用例以解决此问题。