.NET实体框架 - IEnumerable VS. IQueryable的

时间:2011-09-30 06:21:37

标签: entity-framework frameworks entity ienumerable iqueryable

请看这行代码。这是对存储过程的调用,返回ObjectResult<long?>。为了提取长值,我添加了Select:

dbContext.FindCoursesWithKeywords(keywords).Select(l => l.Value);

基于智能感知,此选择返回IEnumerable<long>

我不确定我是否在某处读过它或者只是习惯了这个假设 - 我一直认为当EF API返回IEnumerable(而不是IQueryable)时,这意味着结果已经实现。这意味着他们已被从数据库中删除。

我今天发现我错了(或者这可能是个错误?)。我一直收到错误

  

“不允许新事务,因为还有其他线程   在会话中运行“

基本上,此错误告诉您在db阅读器仍在读取记录时尝试保存更改。

最终我通过(我认为是长镜头)解决了这个问题并添加了ToArray()来实现IEnumerable<long> ...

那么 - 底线 - 我应该期望EF的IEnumerable结果包含尚未实现的结果吗?如果是,那么有没有办法知道IEnumerable是否已实现?

如果这是'duhhh'问题之一,请致谢并道歉......)

4 个答案:

答案 0 :(得分:28)

使用Linq-to-entities时使用

IQueryable =您正在应用程序中构建声明性LINQ查询,LINQ提供程序将其解释为SQL并在服务器上执行。一旦查询被执行(迭代),它将变为IEnumerable,并且对象将根据需要实现迭代=不是立即。

调用存储过程后,您没有使用Linq-to-entities,因为您的应用程序中没有内置声明性查询。查询/ SQL已存在于数据库服务器上,您只是在调用它。这将返回IEnumerable,但同样不会立即实现所有结果。结果将实现为迭代。当您明确要求获取对象时,这是数据库游标/或.NET数据读取器的原理。

所以如果你这样打电话:

foreach (var keyword in dbContext.FindCoursesWithKeywords(keywords)
                                 .Select(l => l.Value))
{
    ...   
}

您正在逐个学习课程(顺便说一句。如果您只对关键词感兴趣,为什么要加载整个课程?)。在您完成或中断循环之前,您的数据阅读器将被打开以获取记录。

如果你这样称呼:

foreach (var keyword in dbContext.FindCoursesWithKeywords(keywords)
                                 .ToList() // or ToArray 
                                 .Select(l => l.Value))
{
    ...
}

您将强制查询立即实现所有结果,循环将在内存中执行而不是打开数据库读取器。

IEnumerableIQueryable之间的差异与提取数据的方式不同,因为IQueryableIEnumerable。不同之处在于支持构造(必须实现这些接口)。

答案 1 :(得分:11)

使用IEnumerable<T>意味着所有进一步的操作都将在C#代码中发生,即linq-to-objects。这并不意味着查询已经执行。

一旦降级为linq-to-objects,此时剩下的所有数据都需要从数据库中获取并发送到.net。这会严重降低性能(例如,linq-to-objects不会使用数据库索引),但另一方面,linq-to-objects更灵活,因为它可以执行任意C#代码而不受限制您的linq提供程序可以转换为SQL。

IEnumerable<T>可以是延迟查询,也可以是已实现的数据。标准linq运算符通常是延迟的,ToArray() / ToList()始终具体化。

答案 2 :(得分:0)

IEnumerable在物化之前不会水合。如果调用存储过程我会认为不需要进一步的过滤器,我的意思是你将参数发送到存储过程以产生所需的数据返回子集。 IEnumerable绑定到存储过程很好。但是,如果要获取表的全部内容,然后在应用程序中进行过滤,则应该有策略。比如,不要ToList()表的IEnumerable,你将实现所有行。有时这会导致内存不足异常。除了为什么没有理由消耗内存。对上下文使用IQueryable,这样就可以过滤数据源中的表,而不是应用程序中的表。作为回答,你必须实现它。 IEnumerable是一个接口,只有实现它才会“初始化”它的类型,并在我的理解中产生一些东西。

答案 3 :(得分:-5)

IEnumerable:LINQ to Object和LINQ to XML。

IQueryable:LINQ to SQL