新事务不允许,因为会话中有其他线程正在运行LINQ To Entity。

150
任何关于为什么会出现问题的想法?
foreach (var p in pp)
{
    ProjectFiles projectFile = (ProjectFiles)p;
    projectFile.Status = Constants.ProjectFiles_ERROR;
    projectFile.DateLastUpdated = DateTime.Now;
    context.SaveChanges();
}

我读到解决此问题的方法是在foreach循环之前一次性获取结果。但我不是已经这样做了吗?在我的情况下,“pp”就是结果集合。


11
“pp”是一次linq查询的结果吗?如果是,您可能需要在循环之前对其进行ToList()操作,以将其与数据库断开连接。 - SouthShoreAK
2
在循环外调用保存更改。 - Mohsin
这里只是一个小指针。推荐的修复方案可能是通过阻止EF在每次保存时不断启动新事务来解决问题。但是,这指出EF中存在的一个问题。这里的逻辑可能不正确。在循环中保存之前,应该启动一个事务,然后在结束时提交所有内容或回滚所有内容。当然,除非这不是所需的逻辑。 - Christian Findlay
2个回答

377

pp 变量不是一组对象的集合,它是一个可以返回对象的枚举器。在使用枚举器时,源必须保持打开状态。

使用 ToList 方法将枚举器实现为一个集合。这将读取枚举器中的所有项并关闭到源的连接,以便您可以将该连接用于其他事情。

foreach (var p in pp.ToList())

18
愿上帝保佑你,@Guffa!!!+1 - NoWar
2
太棒了!它也适用于 pp.ToArray()。 - Ricardo Polo Jaramillo
2
Ricardo,只要它不是IQueryable,它就能正常运行。 - Null Head
@Guffa 我也遇到了完全相同的问题,这个简单的添加对我很有用!谢谢你! - rikket
应该注意到这个问题不是特定于Entity Framework。它与底层的SQL Server SqlConnection对象相关。显然,在这种情况下,Entity Framework认为每次保存都要开始一个事务。这是一个糟糕的想法,也是不使用Entity Framework的理由之一。我猜测代码应该提交所有更改或回滚它们。此代码应包装在单个事务中以实现此目的。EF隐藏了事务处理。 - Christian Findlay

10
一种解决方法是在遍历集合之前调用.ToList()。另外,为了加速代码,请在循环退出后仅调用一次context.SaveChanges()

1
这个陈述似乎并不描述真实情况,因为它与已接受解决方案的断言以及其他回答问题的链接有所不同。看起来更像是在迭代完成之前尝试进行更改保存,而不是使用多个连接的情况。 - theta-fish
是的,这里没有多个连接正在进行中。它与在尝试写入连接同时从连接中读取有关。 - N73k
但是如果我要迭代一百万个项目,我无法将它们全部加载到内存中。必须有一种方法可以在迭代的同时进行更新。 - justin.m.chase
ORM并不适用于更新数百万条记录。它们的作用是填充复杂对象,可能还包括一些CRUD操作,但批量操作应直接在数据库上执行,或者至少通过专门用于批量操作的库来执行。 - Captain Kenpachi
如果您可以通过存储过程或定时作业执行批量操作,那么最好选择这种方式。 - Captain Kenpachi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接