IQueryable,List,IEnumerator之间的区别?
我想知道IQueryable,List,IEnumerator和我应该使用每一个的区别是什么?
例如,当使用LINQ到SQL我会做这样的事情
public List<User> GetUsers()
{
return db.User.where(/* some query here */).ToList();
}
现在我想知道是否应该使用IQueryable,但我不确定在列表中使用它的优点。
IQueryable<T>
旨在允许查询提供者(例如,LINQ to SQL或实体框架之类的ORM)使用查询中包含的表达式将请求转换为另一种格式。 换句话说,LINQ-to-SQL将查看您正在使用的实体的属性以及您正在进行的比较,并实际创建一条SQL语句来表示(希望)一个等效请求。
IEnumerable<T>
比更通用IQueryable<T>
尽管的所有实例IQueryable<T>
实现IEnumerable<T>
并只定义的序列。 但是, Enumerable
类中有扩展方法可用于定义该接口上的某些查询类型运算符,并使用普通代码来评估这些条件。
List<T>
只是一个输出格式,它实现IEnumerable<T>
,与查询没有直接关系。
换句话说,当您使用IQueryable<T>
,您正在定义一个表达式,并将其转换为其他内容。 即使您正在编写代码,该代码也不会执行,只会被检查并转换为其他内容,如实际的SQL查询。 正因为如此,这些表达式中只有某些东西是有效的。 例如,您不能调用您在这些表达式中定义的普通函数,因为LINQ-to-SQL不知道如何将您的调用转换为SQL语句。 不幸的是,这些限制中的大部分仅在运行时进行评估。
当您使用IEnumerable<T>
进行查询时,您正在使用LINQ-to-Objects,这意味着您正在编写用于评估查询或转换结果的实际代码,所以通常没有任何限制你可以做什么。 您可以自由地从这些表达式中调用其他函数。
使用LINQ to SQL
要与上述区别携手,牢记在实践中如何解决这一问题也很重要。 当您在LINQ to SQL中针对数据上下文类编写查询时,它会生成一个IQueryable<T>
。 无论您对IQueryable<T>
本身做什么,都会变成SQL,因此您的筛选和转换将在服务器上完成。 无论你如何对待IEnumerable<T>
,都将在应用程序级完成。 有时这是可取的(例如在需要使用客户端代码的情况下),但在很多情况下,这是无意的。
例如,如果我有一个代表Customer
表的Customers
属性的上下文,并且每个客户都有一个CustomerId
列,那么我们来看看执行此查询的两种方法:
var query = (from c in db.Customers where c.CustomerId == 5 select c).First();
这将生成SQL,查询数据库中CustomerId
等于5的Customer
记录。如下所示:
select CustomerId, FirstName, LastName from Customer where CustomerId = 5
现在,如果我们通过使用AsEnumerable()
扩展方法将Customers
转换为IEnumerable<Customer>
会发生什么?
var query = (from c in db.Customers.AsEnumerable() where c.CustomerId == 5 select c).First();
这个简单的改变会产生严重的后果。 由于我们将Customers
转变为IEnumerable<Customer>
,这会将整个表格带回并在客户端对其进行过滤(严格地说,这将使表中的每一行都带回,直到遇到符合标准的行,但重点是相同的)。
ToList()
直到现在,我们只讨论了IQueryable
和IEnumerable
。 这是因为它们是类似的免费接口。 在这两种情况下,你都在定义一个查询; 也就是说,您正在定义在哪里查找数据,要应用哪些过滤器以及要返回哪些数据。 这两个都是查询
query = from c in db.Customers where c.CustomerId == 5 select c;
query = from c in db.Customers.AsEnumerable() where c.CustomerId == 5 select c;
就像我们已经讲到的那样,第一个查询使用IQueryable
,第二个使用IEnumerable
。 然而,在这两种情况下,这只是一个查询。 定义查询实际上不会对数据源做任何事情。 当代码开始遍历列表时,查询实际上被执行。 这可以发生多种方式; 一个foreach
循环,调用ToList()
等。
该查询在第一次迭代时执行。 如果您要在query
调用ToList()
两次,则最终会得到两个具有完全不同对象的列表。 它们可能包含相同的数据,但它们会是不同的参考。
在评论后编辑
我只想清楚什么时候客户端和服务器端完成之间的区别。 如果你引用的是IQueryable<T>
作为IEnumerable<T>
它是一个仅将查询做IEnumerable<T>
将在客户端完成。 例如,假设我有这张表和一个LINQ-to-SQL上下文:
Customer
-----------
CustomerId
FirstName
LastName
我首先构造一个基于FirstName
的查询。 这将创建一个IQueryable<Customer>
:
var query = from c in db.Customers where c.FirstName.StartsWith("Ad") select c;
现在我将该查询传递给一个带有IEnumerable<Customer>
的函数,并根据LastName
一些筛选:
public void DoStuff(IEnumerable<Customer> customers)
{
foreach(var cust in from c in customers where c.LastName.StartsWith("Ro"))
{
Console.WriteLine(cust.CustomerId);
}
}
我们在这里完成了第二个查询,但是它正在IEnumerable<Customer>
。 这里将发生什么是第一个查询将被评估,运行这个SQL:
select CustomerId, FirstName, LastName from Customer where FirstName like 'Ad%'
因此,我们要带回FirstName
以"Ad"
开头的所有人。 请注意,这里没有关于LastName
。 这是因为它被客户端过滤掉了。
一旦它带回这些结果,程序就会迭代结果并仅传递LastName
以"Ro"
开头的记录。 这样做的缺点是我们带回了数据 - 即所有的LastName
不以"Ro"
开头的行 - 可能已被服务器过滤掉。
IQueryable<T>
:抽象数据库访问,支持查询的懒惰评估
List<T>
:条目的集合。 不支持懒惰评估
IEnumerator<T>
:提供迭代和IEnumerable<T>
( IQueryable<T>
和List<T>
都是)的能力,
该代码的问题非常简单 - 它在调用时始终执行查询。 如果您要返回db.User.Where(...)
(它是一个IQueryable<T>
),您应该对查询进行评估,直到实际需要(迭代)为止。 另外,如果该方法的用户需要指定更多的谓词,那么这些谓词也会在数据库中执行,这使得它更快。
当你想要某个实体的强类型集合时,使用iList
或List<item>
。
当你想将愚蠢的数据作为一个对象集合使用时,使用Iqueryable
和Ienumurator
,它将作为一个松散的类型集合返回,并且不会应用任何限制。
我宁愿使用List<type>
因为使用列表包装并强制类型集合中的结果我的结果集。
此外,使用列表可让您添加,排序并将图层转换为Array,Ienumurator或Queryable。
链接地址: http://www.djcxy.com/p/21251.html上一篇: Differences between IQueryable, List, IEnumerator?
下一篇: What's the difference between IQueryable and IEnumerable