返回IEnumerable <T>与IQueryable <T>
返回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;
双方都会被推迟执行,并且什么时候应该比另一方优先?
是的,两者都会让你延期执行。
不同之处在于IQueryable<T>
是允许LINQ到SQL(LINQ到任何事情)的接口。 因此,如果您进一步优化对IQueryable<T>
查询,那么将尽可能在数据库中执行该查询。
对于IEnumerable<T>
情况,它将是LINQ到对象,这意味着所有匹配原始查询的对象都必须从数据库加载到内存中。
在代码中:
IQueryable<Customer> custs = ...;
// Later on...
var goldCustomers = custs.Where(c => c.IsGold);
该代码将执行SQL以仅选择黄金客户。 另一方面,下面的代码将执行数据库中的原始查询,然后过滤掉内存中的非黄金客户:
IEnumerable<Customer> custs = ...;
// Later on...
var goldCustomers = custs.Where(c => c.IsGold);
这是一个非常重要的区别,使用IQueryable<T>
在很多情况下可以使您免于从数据库中返回太多行。 另一个主要的例子是分页:如果你在IQueryable
上使用Take
和Skip
,你只会得到请求的行数; 在IEnumerable<T>
上这样做会导致你所有的行都被加载到内存中。
最好的答案是好的,但它没有提到解释两个接口如何不同的表达树。 基本上,有两套相同的LINQ扩展。 Where()
, Sum()
, Count()
, FirstOrDefault()
等都有两个版本:一个接受函数,另一个接受表达式。
IEnumerable
版本签名是: Where(Func<Customer, bool> predicate)
IQueryable
版本签名是: Where(Expression<Func<Customer, bool>> predicate)
你可能一直在使用这两种方法而没有意识到它,因为两者都使用相同的语法来调用:
例如, Where(x => x.City == "<City>")
对IEnumerable
和IQueryable
在IEnumerable
集合上使用Where()
时,编译器将编译后的函数传递给Where()
在IQueryable
集合上使用Where()
时,编译器将表达式树传递给Where()
。 表达式树就像反射系统,但代码。 编译器将你的代码转换成一个数据结构,用一种易于理解的格式来描述你的代码的功能。
为什么要打扰这个表达树的东西? 我只想要Where()
来过滤我的数据。 主要原因是EF和Linq2SQL ORM都可以将表达式树直接转换为SQL,其代码执行速度会更快。
噢,这听起来像是一个免费的性能提升,在这种情况下,我应该使用AsQueryable()
吗? 不, IQueryable
只有在底层数据提供者可以对它做些什么时才有用。 将常规List
转换为IQueryable
不会带来任何好处。
是的,两者都使用延期执行。 让我们来说明使用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
的属性,它存储了一个树形表达式,当我们在我们的示例中使用result
(称为延迟执行)时,该表达式将开始创建,最后,该表达式将转换为SQL查询以在数据库引擎上运行。
上一篇: Returning IEnumerable<T> vs. IQueryable<T>
下一篇: define() vs const