升级到EntityFramework 6.1.3,现在正在接收上下文异常
本文关键字:异常 上下文 EntityFramework | 更新日期: 2023-09-27 18:24:06
我最近从实体框架5升级到实体框架6.1.3。
以下代码使用相同连接的多个上下文,以前在EF5:中运行良好
var Ids = MyDbContext.MyObject.Select(x => x.Id).Take(5).AsEnumerable();
var myObjects = MyDbContext2.MyObject.Where(x => Ids.Contains(x.Id)).ToList();
在EF6中,我收到:
指定的LINQ表达式包含对以下查询的引用与不同的上下文相关联。描述:未处理的在执行当前web请求期间发生异常。请查看堆栈跟踪以了解有关错误和它在代码中的来源。
异常详细信息:System.NotSupportedException:指定的LINQ表达式包含对与关联的查询的引用不同的语境。
实体框架中做了哪些更改以阻止此操作?我有没有办法在不更改代码的情况下让它工作?
将第一行从.AsEnumerable()
更改为.ToList()
。
https://msdn.microsoft.com/en-us/data/hh949853.aspx#_Query_Plan_Caching
根据本文档,在EF 6中对Contains
处理进行了更改,以优化生成底层SQL查询的方式。
只是在黑暗中拍摄而不看EF6的代码:
IEnumerable通常是一种延迟执行,在您以某种方式引用数据之前不会影响数据库。从框架的角度来看,这不是一个整数或长的列表,而是一个需要在不同上下文中执行的查询。由于它在不同的上下文中处于查询的中间,SQL解析器可能在使用新的处理方法解决它时遇到了问题。IEnumerable是Queryable和loaded之间的一种中途状态。我猜他们为优化所做的任何更改都不会再执行未完成的查询,而且如果引用的对象不是上下文的一部分,无论它是什么,它都会立即短路到异常
这也是为什么将其更改为List()
可以使其工作的原因。您正在处理一个基元列表,而不是一个未解析的查询。
他们为什么要做出改变?我想他们有自己的原因(甚至超出了优化范围)。我可以想到的是,它可以防止查询生成部分修改IEnumerable的加载状态,以消除可能不需要的副作用。
您可以添加ToDictionary()
:
var Ids = (
from x in MyDbContext.MyObject.Select()
where x.Contains(x.Id)
select x
).ToDictionary(x => x.Key).Keys.ToList();
var myObjects = (
from y in MyDbContext2.MyObject
where y => Ids.Contains(y.Id).ToList()
).ToList();
return myObjects;