返回IQueryable<T>和IEnumerable<T>之间的区别是什么,什么时候应该优先于另一个?
IQueryable<Customer> custs = from c in db.Customers
where c.City == "<City>"
select c;
IEnumerable<Customer> custs = from c in db.Customers
where c.City == "<City>"
select c;
两者都将被延迟执行,何时应该优先于其中一个?
是的,两者都使用延迟执行。让我们使用SQL Server分析器....来说明两者的区别
当我们运行以下代码时:
MarketDevEntities db = new MarketDevEntities();
IEnumerable<WebLog> first = db.WebLogs;
var second = first.Where(c => c.DurationSeconds > 10);
var third = second.Where(c => c.WebLogID > 100);
var result = third.Where(c => c.EmailAddress.Length > 11);
Console.Write(result.First().UserName);
在SQL Server分析器中,我们发现一个命令等于:
"SELECT * FROM [dbo].[WebLog]"
在有100万条记录的WebLog表上运行这段代码大约需要90秒。
因此,所有的表记录都作为对象加载到内存中,然后每个. where()都将是内存中针对这些对象的另一个过滤器。
当我们在上面的例子(第二行)中使用IQueryable而不是IEnumerable时:
在SQL Server分析器中,我们发现一个命令等于:
"SELECT TOP 1 * FROM [dbo].[WebLog] WHERE [DurationSeconds] > 10 AND [WebLogID] > 100 AND LEN([EmailAddress]) > 11"
使用IQueryable运行这段代码大约需要4秒钟。
IQueryable有一个名为Expression的属性,它存储了一个树表达式,当我们在示例中使用结果时开始创建这个树表达式(称为延迟执行),在结束时,这个表达式将被转换为一个SQL查询,在数据库引擎上运行。
除了前两个非常好的答案(由driis和Jacob):
IEnumerable
接口在系统中。集合名称空间。
IEnumerable对象表示内存中的一组数据,并且只能根据这些数据向前移动。由IEnumerable对象表示的查询立即完整地执行,因此应用程序可以快速地接收到数据。
当执行查询时,IEnumerable加载所有数据,如果我们需要对其进行筛选,筛选本身是在客户端完成的。
可查询接口位于系统中。Linq命名空间。
IQueryable对象提供了对数据库的远程访问,并允许您以从头到尾的直接顺序或反向顺序在数据中导航。在创建查询的过程中,返回的对象是IQueryable,查询是优化的。因此,在执行过程中消耗的内存更少,网络带宽更少,但同时它的处理速度比返回IEnumerable对象的查询稍微慢一些。
选择什么?
如果您需要返回的整个数据集,那么最好使用IEnumerable,它提供了最大的速度。
如果你不需要整个返回的数据集,而只是一些过滤后的数据,那么最好使用IQueryable。
我最近遇到了IEnumerable v. IQueryable问题。所使用的算法首先执行IQueryable查询以获得一组结果。然后将这些元素传递给foreach循环,并将这些元素实例化为实体框架(Entity Framework, EF)类。然后在Linq to Entity查询的from子句中使用这个EF类,导致结果为IEnumerable。
我对EF和实体的Linq相当陌生,所以花了一段时间才弄清楚瓶颈是什么。使用MiniProfiling,我找到了查询,然后将所有单独的操作转换为单个IQueryable Linq for Entities查询。IEnumerable执行了15秒,IQueryable执行了0.5秒。其中涉及三个表,在阅读本文后,我相信IEnumerable查询实际上形成了三个表的交叉积并过滤了结果。
尝试使用IQueryables作为经验法则,分析您的工作,使您的更改可测量。