IQueryable、List、IEnumerator 之间的区别? [英] Differences between IQueryable, List, IEnumerator?

查看:31
本文介绍了IQueryable、List、IEnumerator 之间的区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道 IQueryable、List、IEnumerator 之间的区别是什么以及我应该何时使用它们?

I am wondering what the difference between IQueryable, List, IEnumerator is and when I should use each one?

例如,当使用 Linq to SQL 时,我会做这样的事情:

For instance when using Linq to SQL I would do something like this:

public List<User> GetUsers()
{
   return db.User.where(/* some query here */).ToList();
}

现在我想知道是否应该改用 IQueryable.我不确定在列表中使用它的优势.

Now I am wondering if I should be using IQueryable instead. I am unsure of the advantages of using it over the list.

推荐答案

IQueryable 旨在允许查询提供程序(例如,像 LINQ to SQL 或实体框架这样的 ORM)使用查询中包含的表达式将请求转换为另一种格式.换句话说,LINQ-to-SQL 会查看您正在使用的实体的属性以及您进行的比较,并实际创建一个 SQL 语句来表达(希望如此)一个等效的请求.

IQueryable<T> is intended to allow a query provider (for example, an ORM like LINQ to SQL or the Entity Framework) to use the expressions contained in a query to translate the request into another format. In other words, LINQ-to-SQL looks at the properties of the entities that you're using along with the comparisons you're making and actually creates a SQL statement to express (hopefully) an equivalent request.

IEnumerableIQueryable 更通用(尽管 IQueryable 的所有实例都实现了 IEnumerable<;T>) 并且只定义一个序列.但是,Enumerable 类中有一些扩展方法可以在该接口上定义一些查询类型的运算符,并使用普通代码来评估这些条件.

IEnumerable<T> is more generic than IQueryable<T> (though all instances of IQueryable<T> implement IEnumerable<T>) and only defines a sequence. However, there are extension methods available within the Enumerable class that define some query-type operators on that interface and use ordinary code to evaluate these conditions.

List 只是一种输出格式,虽然它实现了IEnumerable,但与查询没有直接关系.

List<T> is just an output format, and while it implements IEnumerable<T>, is not directly related to querying.

换句话说,当您使用 IQueryable 时,您正在定义一个 表达式,该表达式被转换为其他内容.即使您正在编写代码,该代码也永远不会被执行,它只会被检查并转化为其他内容,例如实际的 SQL 查询.因此,在这些表达式中只有某些内容是有效的.例如,您不能调用从这些表达式中定义的普通函数,因为 LINQ-to-SQL 不知道如何将您的调用转换为 SQL 语句.不幸的是,这些限制中的大部分仅在运行时进行评估.

In other words, when you're using IQueryable<T>, you're defining an expression that gets translated into something else. Even though you're writing code, that code never gets executed, it only gets inspected and turned into something else, like an actual SQL query. Because of this, only certain things are valid within these expressions. For instance, you cannot call an ordinary function that you define from within these expressions since LINQ-to-SQL doesn't know how to turn your call into a SQL statement. Most of these restrictions are only evaluated at runtime, unfortunately.

当您使用 IEnumerable 进行查询时,您使用的是 LINQ-to-Objects,这意味着您正在编写用于评估查询或转换结果的实际代码,因此,一般而言,您可以做什么没有任何限制.您可以从这些表达式中自由调用其他函数.

When you use IEnumerable<T> for querying, you're using LINQ-to-Objects, which means you are writing the actual code that is used for evaluating your query or transforming the results, so there are, in general, no restrictions on what you can do. You can call other functions from within these expressions freely.

使用 LINQ to SQL

结合上述区别,记住这在实践中是如何运作的也很重要.当您针对 LINQ to SQL 中的数据上下文类编写查询时,它会生成一个 IQueryable.无论您对IQueryable 本身做什么都将转化为SQL,因此您的过滤和转换将在服务器上完成.无论您对 作为 IEnumerable 做什么,都将在应用程序级别完成.有时这是可取的(例如,在您需要使用客户端代码的情况下),但在许多情况下这是无意的.

Going hand-in-hand with the distinction above, it's also important to bear in mind how this works out in practice. When you write a query against a data context class in LINQ to SQL, it produces an IQueryable<T>. Whatever you do against the IQueryable<T> itself is going to get turned into SQL, so your filtering and transformation will be done on the server. Whatever you do against this as an IEnumerable<T>, will be done at the application level. Sometimes this is desirable (in the case where you need to make use of a client-side code, for example), but in many cases this is unintentional.

例如,如果我有一个带有 Customers 属性的上下文表示 Customer 表,并且每个客户都有一个 CustomerId 列,让我们看看做这个查询的两种方法:

For example, if I had a context with a Customers property representing a Customer table, and each customer has a CustomerId column, let's look at two ways to do this query:

var query = (from c in db.Customers where c.CustomerId == 5 select c).First();

这将生成查询数据库中 Customer 记录的 SQL,其中 CustomerId 等于 5.类似于:

This will produce SQL that queries the database for the Customer record with a CustomerId equaling 5. Something like:

select CustomerId, FirstName, LastName from Customer where CustomerId = 5

现在,如果我们使用 AsEnumerable() 扩展方法将 Customers 变成 IEnumerable 会发生什么?

Now, what happens if we turn Customers into an IEnumerable<Customer> by using the AsEnumerable() extension method?

var query = (from c in db.Customers.AsEnumerable() where c.CustomerId == 5 select c).First();

这个简单的改变带来了严重的后果.由于我们将 Customers 转换为 IEnumerable,这将带回整个表并在客户端对其进行过滤(好吧,严格来说这将带回表格中的每一行直到遇到符合条件的行,但要点是一样的).

This simple change has a serious consequence. Since we're turning Customers into an IEnumerable<Customer>, this will bring the entire table back and filter it on the client side (well, strictly speaking this will bring back every row in the table until it encounters one that fits the criteria, but the point is the same).

ToList()

到目前为止,我们只讨论了 IQueryableIEnumerable.这是因为它们是相似的、互补的接口.在这两种情况下,您都在定义一个查询;也就是说,您要定义在哪里查找数据,什么过滤器应用,以及什么返回数据.这两个都是查询

Up until now, we've only talked about IQueryable and IEnumerable. This is because they are similar, complimentary interfaces. In both cases, you're defining a query; that is, you're defining where to find the data, what filters to apply, and what data to return. Both of these are queries

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()

Like we've talked about, the first query is using IQueryable and the second uses IEnumerable. In both cases, however, this is just a query. Defining the query doesn't actually do anything against the data source. The query is actually executed when code begins to iterate over the list. This can happen multiple ways; a foreach loop, calling ToList(), etc.

查询在第一次每次迭代时执行.如果你在 query 上调用 ToList() 两次,你最终会得到两个具有完全不同对象的列表.它们可能包含相同的数据,但它们将是不同的引用.

The query is executed the first and every time it's iterated. If you were to call ToList() on query two times, you would end up with two lists with completely distinct objects. They might contain the same data, but they would be different references.

评论后编辑

我只想弄清楚什么时候在客户端完成和什么时候在服务器端完成之间的区别.如果您将 IQueryable 引用为 IEnumerable查询在之后完成这是一个 IEnumerable 将在客户端完成.例如,假设我有这个表和一个 LINQ-to-SQL 上下文:

I just want to be clear about the distinction between when things are done client-side and when they're done server-side. If you're referencing an IQueryable<T> as an IEnumerable<T>, only the querying done after it's an IEnumerable<T> will be done client-side. For example, say I have this table and a LINQ-to-SQL context:

Customer
-----------
CustomerId
FirstName
LastName

我首先根据 FirstName 构造一个查询.这将创建一个 IQueryable:

I first construct a query based on FirstName. This creates an IQueryable<Customer>:

var query = from c in db.Customers where c.FirstName.StartsWith("Ad") select c;

现在我将该查询传递给一个函数,该函数接受一个 IEnumerable 并根据 LastName 进行一些过滤:

Now I pass that query to a function that takes an IEnumerable<Customer> and does some filtering based on 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 上完成的.这里将要发生的是第一个查询将被评估,运行这个 SQL:

We've done a second query here, but it's being done on an IEnumerable<Customer>. What's going to happen here is that the first query will be evaluated, running this SQL:

select CustomerId, FirstName, LastName from Customer where FirstName like 'Ad%'

因此,我们将带回所有 FirstNameAd" 开头的人.请注意,这里没有关于 LastName 的内容.那是因为它被客户端过滤掉了.

So we're going to bring back everyone whose FirstName starts with "Ad". Note that there's nothing in here about LastName. That's because it's being filtered out client-side.

一旦它带回这些结果,程序将迭代结果并只传递LastNameRo" 开头的记录.这样做的缺点是我们带回了数据——即所有 LastName Ro" 开头的行——可能已在服务器上过滤掉.

Once it brings back these results, the program will then iterate over the results and deliver only the records whose LastName starts with "Ro". The downside to this is that we brought back data--namely, all rows whose LastName doesn't start with "Ro"--that could have been filtered out on the server.

这篇关于IQueryable、List、IEnumerator 之间的区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆