我最近在我们的一个大型项目中将 EF 6.1.3 升级到 6.2.0,它破坏了我们大量的 LINQ 查询。启用 MultipleActiveResultSets 会使一切再次正常工作,但我很难理解这种变化。我们已经使用 EF 多年,并且经历了多个主要版本更改,没有出现任何问题。如果我简单地恢复到 6.1.3,一切都会按预期再次运行 -事实上,即使我在 6.1.3 中明确禁用 MARS,一切都正常.
让我举几个简单的例子。第一个问题是嵌套查询:
foreach(var row in dbSet.Where(<condition>))
foreach(var innerRow in otherDbSet.Where(_ => _.Property == row.Property))
这在 6.1.3 中工作正常,但在 6.2.0 中会抛出“已经有一个打开的 DataReader...”异常。我了解异常的本质,我可以通过在外部查询上调用 ToList() 来首先将结果推送到内存中来解决这个问题 - 我不明白的是为什么我不必在 6.1.3 中这样做(即使 MARS 已禁用)。简单地将整个外部集加载到内存中并不总是可取的。
这似乎也会影响延迟加载的属性。例如,我们从简单的查询构建组合框,如下所示:
return db.Collection
.Where(<condition>)
.AsEnumerable()
.Select(_ => new ListItem(_.Id, _.LazyNavigationProperty.Description))
.ToList();
这在 6.1.3 中工作正常,但在 6.2.0 中再次抛出“已经有一个打开的 DataReader...”异常。解决方法是我现在必须立即加载导航属性。
最终我没有明确的问题,我只是想理解为什么次要版本更新似乎会导致查询处理方式发生重大破坏性变化。
展望未来,这会影响太多的查询,需要我们重构。当我研究这个问题时,我看到了关于启用 MARS 的模糊警告,但没有人真正给出任何具体信息。是否有令人信服的理由不启用它?
您收到此错误是因为您在尝试打开另一个结果集时迭代结果集(而第一个结果集尚未完成)-> 某种延迟加载(在您的情况下是第一个“for every”迭代)->有很多方法可以解决这个问题,正如您已经亲眼所见:使用 toList (首先放入内存),因为它不再使用 datareader 来打开集合。
看起来它可能与 6.2 中的错误修复有关(发行说明:https://entityframework.net/ef-version-history https://entityframework.net/ef-version-history) - 看起来与以下内容相关:“错误:重试查询或 SQL 命令失败,并显示“SqlParameter 已包含在另一个 SqlParameterCollection 中。”)
关于启用 MARS:
您可以在这里找到特别警告:
https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/sql/enabling-multiple-active-result-sets https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/sql/enabling-multiple-active-result-sets
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)