我想澄清一些事情,因为似乎相互矛盾的反应(主要围绕IEnumerable)。
IQueryable扩展了IEnumerable接口。(你可以发送一个IQueryable给一个期望IEnumerable而没有错误的对象。)
(2) IQueryable和IEnumerable LINQ在迭代结果集时都尝试延迟加载。(注意,可以在每种类型的接口扩展方法中看到实现。)
换句话说,IEnumerables不是独占的“内存中”。IQueryables并不总是在数据库上执行。IEnumerable必须将数据加载到内存中(一旦检索到,可能是惰性的),因为它没有抽象数据提供程序。IQueryables依赖于抽象提供者(如LINQ-to-SQL),尽管这也可以是. net内存中的提供者。
样例用例
(a)从EF上下文检索IQueryable记录列表。(内存中没有记录。)
(b)将IQueryable传递给模型为IEnumerable的视图。(有效。IQueryable扩展IEnumerable。)
(c)在视图中遍历并访问数据集的记录、子实体和属性。(可能会导致异常!)
可能的问题
IEnumerable尝试延迟加载,你的数据上下文过期了。由于提供程序不再可用而引发异常。
(2)实体框架实体代理已启用(默认),并且您尝试访问具有过期数据上下文的相关(虚拟)对象。同(1)。
(3)多活动结果集(MARS)。如果你在foreach(var record in resultSet)块中遍历IEnumerable,同时尝试访问record. childentity。childProperty,由于数据集和关系实体的惰性加载,您可能最终会得到MARS。如果在连接字符串中未启用该选项,则会导致异常。
解决方案
我发现在连接字符串中启用MARS工作不可靠。我建议你避免MARS,除非它被很好地理解和明确地渴望。
执行查询并通过调用resultList = resultSet.ToList()来存储结果,这似乎是确保实体位于内存中的最直接的方法。
在访问相关实体的情况下,可能仍然需要数据上下文。或者,您可以禁用实体代理,并显式地从DbSet中包含相关实体。