IQueryable,List,IEnumerator之间的区别?

我想知道IQueryable,List,IEnumerator和我何时应该使用每个的区别? 例如,当使用Linq to 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,用于查询数据库中的
Customer
记录,其中
CustomerId
等于5.类似于:
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>
和ѭ7都是) 该代码的问题非常简单 - 它总是在调用时执行查询。如果你要返回
db.User.Where(...)
(这是一个
IQueryable<T>
),你将持有对查询的评估,直到它实际需要(迭代结束)。此外,如果该方法的用户需要指定更多谓词,那么这些谓词也会在数据库中执行,这样会更快。     
当您需要某个实体的强类型集合时,请使用
iList
List<item>
。 当你想要将哑数据作为一个对象集合时,使用
Iqueryable
Ienumurator
,它将作为一个松散类型集合返回,并且不会应用任何限制。 我宁愿使用
List<type>
因为使用列表换行并在强类型集合中强制转换我的结果集。 此外,使用列表将使您能够添加,排序和转换图层到Array,Ienumurator或Queryable。     

要回复问题请先登录注册