我正在使用实体框架,偶尔我会得到这个错误。

EntityCommandExecutionException
{"There is already an open DataReader associated with this Command which must be closed first."}
   at System.Data.EntityClient.EntityCommandDefinition.ExecuteStoreCommands...

即使我没有做任何手动连接管理。

此错误间歇性地发生。

触发错误的代码(为方便阅读而缩短):

        if (critera.FromDate > x) {
            t= _tEntitites.T.Where(predicate).ToList();
        }
        else {
            t= new List<T>(_tEntitites.TA.Where(historicPredicate).ToList());
        }

使用Dispose模式以便每次都打开新的连接。

using (_tEntitites = new TEntities(GetEntityConnection())) {

    if (critera.FromDate > x) {
        t= _tEntitites.T.Where(predicate).ToList();
    }
    else {
        t= new List<T>(_tEntitites.TA.Where(historicPredicate).ToList());
    }

}

仍然有问题

为什么EF不重用一个连接,如果它已经打开。


当前回答

我注意到,当我发送一个iquerible到视图并在双foreach中使用它时,这个错误发生了,其中内部foreach也需要使用连接。简单的例子(ViewBag。parent可以是iqueryable或者DbSet):

foreach (var parent in ViewBag.parents)
{
    foreach (var child in parent.childs)
    {

    }
}

简单的解决方案是在使用集合之前对其使用. tolist()。还要注意,MARS不能与MySQL一起工作。

其他回答

我注意到,当我发送一个iquerible到视图并在双foreach中使用它时,这个错误发生了,其中内部foreach也需要使用连接。简单的例子(ViewBag。parent可以是iqueryable或者DbSet):

foreach (var parent in ViewBag.parents)
{
    foreach (var child in parent.childs)
    {

    }
}

简单的解决方案是在使用集合之前对其使用. tolist()。还要注意,MARS不能与MySQL一起工作。

尝试在连接字符串中设置MultipleActiveResultSets=true。 这允许在数据库上进行多任务处理。

Server=yourserver ;AttachDbFilename=database;User Id=sa;Password=blah ;MultipleActiveResultSets=true;App=EntityFramework

这对我很有用……无论你的连接是在app.config中还是通过编程方式设置的… 希望这对大家有帮助

It is not about closing connection. EF manages connection correctly. My understanding of this problem is that there are multiple data retrieval commands executed on single connection (or single command with multiple selects) while next DataReader is executed before first one has completed the reading. The only way to avoid the exception is to allow multiple nested DataReaders = turn on MultipleActiveResultSets. Another scenario when this always happens is when you iterate through result of the query (IQueryable) and you will trigger lazy loading for loaded entity inside the iteration.

在启用MARS和将整个结果集检索到内存之间有一个很好的中间地带,那就是在初始查询中只检索id,然后循环遍历实现每个实体的id。

例如(使用这个答案中的“博客和帖子”样本实体):

using (var context = new BlogContext())
{
    // Get the IDs of all the items to loop through. This is
    // materialized so that the data reader is closed by the
    // time we're looping through the list.
    var blogIds = context.Blogs.Select(blog => blog.Id).ToList();

    // This query represents all our items in their full glory,
    // but, items are only materialized one at a time as we
    // loop through them.
    var blogs =
        blogIds.Select(id => context.Blogs.First(blog => blog.Id == id));

    foreach (var blog in blogs)
    {
        this.DoSomethingWith(blog.Posts);

        context.SaveChanges();
    }
}

这样做意味着您只需将几千个整数拉入内存,而不是将数千个完整的对象图拉入内存,这将最小化内存使用,同时允许您在不启用MARS的情况下逐项工作。

从示例中可以看到,这样做的另一个好处是,您可以在循环遍历每个项时保存更改,而不必等到循环结束(或其他类似的解决方法),即使启用了MARS也需要这样做(参见这里和这里)。

你得到这个错误,当你试图迭代的集合是一种惰性加载(iquerible)。

foreach (var user in _dbContext.Users)
{    
}

将iquerible集合转换为其他可枚举集合将解决这个问题。 例子

_dbContext.Users.ToList()

注意:. tolist()每次都会创建一个新的集合,如果你在处理大数据,它会导致性能问题。