请考虑以下片段:
IQueryable<Person> pQ = from p in db.People select p;
IEnumerable<Person> pE = pQ;
Console.WriteLine(pQ.Count());
Console.WriteLine(pE.Count());
两者都给出相同的结果,但是如果跟踪生成的SQL,则IQueryable
版本将使用COUNT
发出查询,而IEnumerable
版本将仅发出SELECT
,拉入所有行并进行计数在内存中,这可能非常低效。同样适用于其他方法,例如Sum()
和Average()
,并且在EF6和EF Core 3中都存在。
原因是Count()
是扩展方法,因此绑定到变量的静态类型(在第一种情况下为IQueryable
,在第二种情况下为IEnumerable
),而不是动态类型(两种情况下都相同) ,因为它是同一个对象)。
这是一个非常令人讨厌的陷阱,这意味着在这种情况下通常最好避免IEnumerable
。但是,有一种解决方法:
Console.WriteLine(pE.AsQueryable().Count());
这表示SQL
COUNT
已发布。
((注:强制转换为IQueryable
在这里也可以,但通常不会-如果IEnumerable
纯粹是指内存数据,则强制转换将失败,但是AsQueryable()
只会将对象包围在中性包装器。)
我的问题是:由于这个问题很容易被忽略,并且会导致这种低效的行为,为什么对AsQueryable()
的调用不能简单地嵌入到扩展方法的IEnumerable
实现中?
我的问题是:由于这个问题很容易被忽略并且会导致这种低效的行为,为什么对AsQueryable()
的调用不能简单地嵌入到扩展方法的IEnumerable
实现中?