返回 IEnumerable与 IQueryable 比较
返回 IQueryable
与 IEnumerable
之间有什么区别,什么时候应该优先选择其中一个?
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;
两者都会延迟执行吗?什么时候应该优先选择其中一个?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(14)
除了上述内容之外,值得注意的是,如果使用
IQueryable
而不是IEnumerable
,则可能会出现异常:如果
products
则以下内容可以正常工作是一个IEnumerable
:但是,如果
products
是一个IQueryable
并且它尝试访问数据库表中的记录,那么您将收到此错误:这是因为构造了以下查询:
并且 OFFSET 不能有负值。
In addition to the above, it's interesting to note that you can get exceptions if you use
IQueryable
instead ofIEnumerable
:The following works fine if
products
is anIEnumerable
:However if
products
is anIQueryable
and it's trying to access records from a DB table, then you'll get this error:This is because the following query was constructed:
and OFFSET can't have a negative value.
除了前两个非常好的答案(由 driis 和 Jacob 提供):
IEnumerable 对象表示内存中的一组数据,并且只能向前移动该数据。 IEnumerable 对象表示的查询会立即完整地执行,因此应用程序可以快速接收数据。
当执行查询时,IEnumerable会加载所有数据,如果我们需要过滤它,过滤本身是在客户端完成的。
IQueryable 对象提供对数据库的远程访问,并允许您以从头到尾的直接顺序或相反的顺序浏览数据。在创建查询的过程中,返回的对象是IQueryable,查询得到了优化。因此,执行期间消耗的内存更少,网络带宽也更少,但同时它的处理速度可能比返回 IEnumerable 对象的查询稍微慢一些。
选择什么?
如果您需要完整的返回数据集,那么最好使用 IEnumerable,它提供了最大的速度。
如果您不需要整个返回数据集,而只需要一些过滤后的数据,那么最好使用 IQueryable。
In addition to first 2 really good answers (by driis & by Jacob) :
The IEnumerable object represents a set of data in memory and can move on this data only forward. The query represented by the IEnumerable object is executed immediately and completely, so the application receives data quickly.
When the query is executed, IEnumerable loads all the data, and if we need to filter it, the filtering itself is done on the client side.
The IQueryable object provides remote access to the database and allows you to navigate through the data either in a direct order from beginning to end, or in the reverse order. In the process of creating a query, the returned object is IQueryable, the query is optimized. As a result, less memory is consumed during its execution, less network bandwidth, but at the same time it can be processed slightly more slowly than a query that returns an IEnumerable object.
What to choose?
If you need the entire set of returned data, then it's better to use IEnumerable, which provides the maximum speed.
If you DO NOT need the entire set of returned data, but only some filtered data, then it's better to use IQueryable.
我们可以以相同的方式使用两者,它们只是性能不同。
IQueryable 仅以有效的方式针对数据库执行。这意味着它创建一个完整的选择查询并仅获取相关记录。
例如,我们想要选取名字以“Nimal”开头的前 10 位客户。在这种情况下,选择查询将生成为
select top 10 * from Customer where name like 'Nimal%'
。但如果我们使用 IEnumerable,查询将类似于
select * from Customer where name like 'Nimal%'
并且前十名将在 C# 编码级别进行过滤(它从数据库并将它们传递到 C# 中)。We can use both for the same way, and they are only different in the performance.
IQueryable only executes against the database in an efficient way. It means that it creates an entire select query and only gets the related records.
For example, we want to take the top 10 customers whose name start with ‘Nimal’. In this case the select query will be generated as
select top 10 * from Customer where name like ‘Nimal%’
.But if we used IEnumerable, the query would be like
select * from Customer where name like ‘Nimal%’
and the top ten will be filtered at the C# coding level (it gets all the customer records from the database and passes them into C#).我最近遇到了
IEnumerable
v.IQueryable
的问题。所使用的算法首先执行IQueryable
查询以获得一组结果。然后将它们传递到 foreach 循环,并将这些项目实例化为实体框架 (EF) 类。然后,在 Linq to Entity 查询的from
子句中使用该 EF 类,导致结果为IEnumerable
。我对 EF 和 Linq for Entities 相当陌生,因此花了一段时间才找出瓶颈所在。使用 MiniProfiling,我找到了查询,然后将所有单独的操作转换为单个
IQueryable
Linq for Entities 查询。IEnumerable
的执行时间为 15 秒,IQueryable
的执行时间为 0.5 秒。涉及三个表,读完本文后,我相信IEnumerable
查询实际上形成了三个表的叉积并过滤结果。尝试使用 IQueryables 作为经验法则并分析您的工作以使您的更改可衡量。
I recently ran into an issue with
IEnumerable
v.IQueryable
. The algorithm being used first performed anIQueryable
query to obtain a set of results. These were then passed to aforeach
loop, with the items instantiated as an Entity Framework (EF) class. This EF class was then used in thefrom
clause of a Linq to Entity query, causing the result to beIEnumerable
.I'm fairly new to EF and Linq for Entities, so it took a while to figure out what the bottleneck was. Using MiniProfiling, I found the query and then converted all of the individual operations to a single
IQueryable
Linq for Entities query. TheIEnumerable
took 15 seconds and theIQueryable
took 0.5 seconds to execute. There were three tables involved and, after reading this, I believe that theIEnumerable
query was actually forming a three table cross-product and filtering the results.Try to use IQueryables as a rule-of-thumb and profile your work to make your changes measurable.
由于看似相互矛盾的反应(主要围绕 IEnumerable),我想澄清一些事情。
(1)
IQueryable
扩展了IEnumerable
接口。 (您可以将IQueryable
发送到需要IEnumerable
的对象,而不会出现错误。)(2)
IQueryable
和IEnumerable
LINQ 在迭代结果集时尝试延迟加载。 (请注意,可以在每种类型的接口扩展方法中看到实现。)换句话说,
IEnumerables
并不完全是“内存中”的。IQueryables
并不总是在数据库上执行。IEnumerable
必须将内容加载到内存中(一旦检索,可能是延迟加载),因为它没有抽象数据提供程序。IQueryables
依赖于抽象提供程序(如 LINQ-to-SQL),尽管这也可能是 .NET 内存中提供程序。示例用例
(a) 从 EF 上下文中以
IQueryable
形式检索记录列表。 (内存中没有记录。)(b) 将
IQueryable
传递给模型为IEnumerable
的视图。 (有效。IQueryable
扩展了IEnumerable
。)(c) 从视图迭代并访问数据集的记录、子实体和属性。 (可能会导致异常!)
可能的问题
(1)
IEnumerable
尝试延迟加载,并且您的数据上下文已过期。由于提供者不再可用而引发异常。(2) 实体框架实体代理已启用(默认),并且您尝试访问具有过期数据上下文的相关(虚拟)对象。与(1)相同。
(3) 多个活动结果集 (MARS)。如果您在
foreach( var record in resultSet )
块中迭代IEnumerable
并同时尝试访问record.childEntity.childProperty
,那么您由于数据集和关系实体的延迟加载,最终可能会出现 MARS。如果您的连接字符串中未启用它,这将导致异常。解决方案
通过调用
resultList = resultSet.ToList()
执行查询并存储结果这似乎是确保实体位于内存中的最直接方法。如果您正在访问相关实体,您可能仍然需要数据上下文。或者,您也可以禁用实体代理并从
DbSet
中显式包含
相关实体。I would like to clarify a few things due to seemingly conflicting responses (mostly surrounding IEnumerable).
(1)
IQueryable
extends theIEnumerable
interface. (You can send anIQueryable
to something which expectsIEnumerable
without error.)(2) Both
IQueryable
andIEnumerable
LINQ attempt lazy loading when iterating over the result set. (Note that implementation can be seen in interface extension methods for each type.)In other words,
IEnumerables
are not exclusively "in-memory".IQueryables
are not always executed on the database.IEnumerable
must load things into memory (once retrieved, possibly lazily) because it has no abstract data provider.IQueryables
rely on an abstract provider (like LINQ-to-SQL), although this could also be the .NET in-memory provider.Sample use case
(a) Retrieve list of records as
IQueryable
from EF context. (No records are in-memory.)(b) Pass the
IQueryable
to a view whose model isIEnumerable
. (Valid.IQueryable
extendsIEnumerable
.)(c) Iterate over and access the data set's records, child entities and properties from the view. (May cause exceptions!)
Possible Issues
(1) The
IEnumerable
attempts lazy loading and your data context is expired. Exception thrown because provider is no longer available.(2) Entity Framework entity proxies are enabled (the default), and you attempt to access a related (virtual) object with an expired data context. Same as (1).
(3) Multiple Active Result Sets (MARS). If you are iterating over the
IEnumerable
in aforeach( var record in resultSet )
block and simultaneously attempt to accessrecord.childEntity.childProperty
, you may end up with MARS due to lazy loading of both the data set and the relational entity. This will cause an exception if it is not enabled in your connection string.Solution
Execute the query and store results by invoking
resultList = resultSet.ToList()
This seems to be the most straightforward way of ensuring your entities are in-memory.In cases where the you are accessing related entities, you may still require a data context. Either that, or you can disable entity proxies and explicitly
Include
related entities from yourDbSet
.“IEnumerable”和“IQueryable”之间的主要区别在于过滤器逻辑的执行位置。一个在客户端(在内存中)执行,另一个在数据库上执行。
例如,我们可以考虑一个例子,数据库中有一个用户的 10,000 条记录,假设只有 900 条是活跃用户,因此在这种情况下,如果我们使用“IEnumerable”,那么首先它会在内存中加载所有 10,000 条记录,然后然后对其应用 IsActive 过滤器,最终返回 900 个活跃用户。
另一方面,在同样的情况下,如果我们使用“IQueryable”,它将直接在数据库上应用 IsActive 过滤器,该过滤器将直接返回 900 个活跃用户。
The main difference between “IEnumerable” and “IQueryable” is about where the filter logic is executed. One executes on the client side (in memory) and the other executes on the database.
For example, we can consider an example where we have 10,000 records for a user in our database and let's say only 900 out which are active users, so in this case if we use “IEnumerable” then first it loads all 10,000 records in memory and then applies the IsActive filter on it which eventually returns the 900 active users.
While on the other hand on the same case if we use “IQueryable” it will directly apply the IsActive filter on the database which directly from there will return the 900 active users.
有一篇博客文章提供了简短的源代码示例,介绍了
IEnumerable
的滥用如何极大地影响 LINQ 查询性能:实体框架:IQueryable 与 IEnumerable。如果我们深入挖掘并查看源代码,我们可以看到
IEnumerable
:和
IQueryable
执行 了明显不同的扩展方法:第一个返回可枚举迭代器,第二个通过
IQueryable
源中指定的查询提供程序创建查询。There is a blog post with brief source code sample about how misuse of
IEnumerable<T>
can dramatically impact LINQ query performance: Entity Framework: IQueryable vs. IEnumerable.If we dig deeper and look into the sources, we can see that there are obviously different extension methods are perfomed for
IEnumerable<T>
:and
IQueryable<T>
:The first one returns enumerable iterator, and the second one creates query through the query provider, specified in
IQueryable
source.一般来说,您希望保留查询的原始静态类型,直到它变得重要为止。
因此,您可以将变量定义为“var”,而不是
IQueryable<>
或IEnumerable<>
,并且您将知道您没有更改类型。如果您一开始使用的是
IQueryable<>
,您通常希望将其保留为IQueryable<>
,直到有令人信服的理由对其进行更改。这样做的原因是您希望为查询处理器提供尽可能多的信息。例如,如果您只打算使用 10 个结果(您已调用Take(10)
),那么您希望 SQL Server 了解这一点,以便它可以优化其查询计划并向您发送仅您将使用的数据。将类型从
IQueryable<>
更改为IEnumerable<>
的一个令人信服的原因可能是您正在调用一些扩展函数来实现IQueryable<> ;
在您的特定对象中要么无法处理,要么处理效率低下。在这种情况下,您可能希望将类型转换为IEnumerable<>
(通过分配给IEnumerable<>
类型的变量或使用AsEnumerable
扩展方法(例如),以便您调用的扩展函数最终成为Enumerable
类中的函数,而不是Queryable
类中的函数。In general you want to preserve the original static type of the query until it matters.
For this reason, you can define your variable as 'var' instead of either
IQueryable<>
orIEnumerable<>
and you will know that you are not changing the type.If you start out with an
IQueryable<>
, you typically want to keep it as anIQueryable<>
until there is some compelling reason to change it. The reason for this is that you want to give the query processor as much information as possible. For example, if you're only going to use 10 results (you've calledTake(10)
) then you want SQL Server to know about that so that it can optimize its query plans and send you only the data you'll use.A compelling reason to change the type from
IQueryable<>
toIEnumerable<>
might be that you are calling some extension function that the implementation ofIQueryable<>
in your particular object either cannot handle or handles inefficiently. In that case, you might wish to convert the type toIEnumerable<>
(by assigning to a variable of typeIEnumerable<>
or by using theAsEnumerable
extension method for example) so that the extension functions you call end up being the ones in theEnumerable
class instead of theQueryable
class.前面已经说了很多,但回到根源,以更技术的方式:
IEnumerable
是内存中可以枚举的对象集合 - 内存中的对象使迭代成为可能的序列(使得在foreach
循环中变得容易,尽管您只能使用IEnumerator
)。它们原样驻留在内存中。IQueryable
是一个表达式树,它将在某个时刻被转换为其他东西能够枚举最终结果。我想这是大多数人的困惑。它们显然具有不同的内涵。
IQueryable
表示一个表达式树(简单来说是一个查询),一旦调用发布 API,底层查询提供程序就会将其转换为其他内容,例如 LINQ 聚合函数(Sum、Count 等)或 ToList[数组,字典,...]。并且IQueryable
对象还实现IEnumerable
、IEnumerable
,因此如果它们表示查询< /strong> 该查询的结果可以迭代。这意味着 IQueryable 不必只是查询。正确的术语是它们是表达式树。现在这些表达式如何执行以及它们转向什么都取决于所谓的查询提供者(我们可以认为它们是表达式执行器)。
在 Entity Framework 世界中(即神秘的底层数据源提供程序,或查询提供程序) )
IQueryable
表达式转换为本机 T-SQL 查询。Nhibernate
对它们做了类似的事情。您可以按照 LINQ:构建 IQueryable 提供程序 链接,您可能希望为您的产品商店提供程序服务提供自定义查询 API。所以基本上,
IQueryable
对象一直在构建,直到我们显式释放它们并告诉系统将它们重写为 SQL 或其他内容,然后发送到执行链以进行后续处理。就像延迟执行一样,它是一个
LINQ
功能,可以将表达式树方案保存在内存中,并仅根据需要将其发送到执行中,每当针对序列调用某些 API(相同的 Count、ToList 等)时。两者的正确使用在很大程度上取决于您在特定情况下面临的任务。对于众所周知的存储库模式,我个人选择返回
IList
,即IEnumerable
而不是列表(索引器等)。因此,我的建议是仅在存储库中使用 IQueryable,而在代码的其他任何地方使用 IEnumerable。没有说IQueryable
崩溃并破坏关注点分离IQueryable的可测试性问题a> 原则。如果您从存储库中返回一个表达式,消费者可以按照自己的意愿使用持久层。混乱中又添了一点:)(来自评论中的讨论))
它们都不是内存中的对象,因为它们本身不是真正的类型,它们是类型的标记 - 如果您想深入了解的话。但这是有道理的(这就是为什么 MSDN 这么说)将 IEnumerables 视为-内存集合,而 IQueryables 作为表达式树。要点是 IQueryable 接口继承了 IEnumerable 接口,因此如果它表示一个查询,则可以枚举该查询的结果。枚举导致执行与 IQueryable 对象关联的表达式树。
因此,事实上,如果没有内存中的对象,您就无法真正调用任何 IEnumerable 成员。如果你这样做的话它就会进入那里,无论如何,如果它不是空的。 IQueryables 只是查询,而不是数据。
A lot has been said previously, but back to the roots, in a more technical way:
IEnumerable
is a collection of objects in memory that you can enumerate - an in-memory sequence that makes it possible to iterate through (makes it way easy for withinforeach
loop, though you can go withIEnumerator
only). They reside in the memory as is.IQueryable
is an expression tree that will get translated into something else at some point with ability to enumerate over the final outcome. I guess this is what confuses most people.They obviously have different connotations.
IQueryable
represents an expression tree (a query, simply) that will be translated to something else by the underlying query provider as soon as release APIs are called, like LINQ aggregate functions (Sum, Count, etc.) or ToList[Array, Dictionary,...]. AndIQueryable
objects also implementIEnumerable
,IEnumerable<T>
so that if they represent a query the result of that query could be iterated. It means IQueryable don't have to be queries only. The right term is they are expression trees.Now how those expressions are executed and what they turn to is all up to so called query providers (expression executors we can think them of).
In the Entity Framework world (which is that mystical underlying data source provider, or the query provider)
IQueryable
expressions are translated into native T-SQL queries.Nhibernate
does similar things with them. You can write your own one following the concepts pretty well described in LINQ: Building an IQueryable Provider link, for example, and you might want to have a custom querying API for your product store provider service.So basically,
IQueryable
objects are getting constructed all the way long until we explicitly release them and tell the system to rewrite them into SQL or whatever and send down the execution chain for onward processing.As if to deferred execution it's a
LINQ
feature to hold up the expression tree scheme in the memory and send it into the execution only on demand, whenever certain APIs are called against the sequence (the same Count, ToList, etc.).The proper usage of both heavily depends on the tasks you're facing for the specific case. For the well-known repository pattern I personally opt for returning
IList
, that isIEnumerable
over Lists (indexers and the like). So it is my advice to useIQueryable
only within repositories and IEnumerable anywhere else in the code. Not saying about the testability concerns thatIQueryable
breaks down and ruins the separation of concerns principle. If you return an expression from within repositories consumers may play with the persistence layer as they would wish.A little addition to the mess :) (from a discussion in the comments))
None of them are objects in memory since they're not real types per se, they're markers of a type - if you want to go that deep. But it makes sense (and that's why even MSDN put it this way) to think of IEnumerables as in-memory collections whereas IQueryables as expression trees. The point is that the IQueryable interface inherits the IEnumerable interface so that if it represents a query, the results of that query can be enumerated. Enumeration causes the expression tree associated with an IQueryable object to be executed.
So, in fact, you can't really call any IEnumerable member without having the object in the memory. It will get in there if you do, anyways, if it's not empty. IQueryables are just queries, not the data.
一般来说,我建议如下:
如果您希望开发人员能够使用您的方法在执行之前优化您返回的查询,则返回
IQueryable
。如果您想传输一组要枚举的对象,请返回
IEnumerable
。想象一下
IQueryable
它是什么 - 数据的“查询”(如果您愿意,您可以对其进行细化)。IEnumerable
是一组可以枚举的对象(已接收或已创建)。In general terms I would recommend the following:
Return
IQueryable<T>
if you want to enable the developer using your method to refine the query you return before executing.Return
IEnumerable
if you want to transport a set of Objects to enumerate over.Imagine an
IQueryable
as that what it is - a "query" for data (which you can refine if you want to). AnIEnumerable
is a set of objects (which has already been received or was created) over which you can enumerate.两者都会给你延迟执行,是的。
至于哪个优先于另一个,这取决于您的基础数据源是什么。
返回
IEnumerable
将自动强制运行时使用 LINQ to Objects 来查询集合。返回
IQueryable
(顺便说一下,它实现了IEnumerable
)提供了额外的功能,可以将您的查询转换为可能在底层源(LINQ to SQL、LINQ到 XML 等)。Both will give you deferred execution, yes.
As for which is preferred over the other, it depends on what your underlying datasource is.
Returning an
IEnumerable
will automatically force the runtime to use LINQ to Objects to query your collection.Returning an
IQueryable
(which implementsIEnumerable
, by the way) provides the extra functionality to translate your query into something that might perform better on the underlying source (LINQ to SQL, LINQ to XML, etc.).是的,两者都使用延迟执行。让我们使用 SQL Server 探查器来说明差异......
当我们运行以下代码时:
在 SQL Server 探查器中,我们发现一个命令等于:
针对具有 100 万个 WebLog 表运行该代码块大约需要 90 秒记录。
因此,所有表记录都作为对象加载到内存中,然后对于每个 .Where() ,它将成为内存中针对这些对象的另一个过滤器。
当我们在上面的示例(第二行)中使用
IQueryable
而不是IEnumerable
时:在 SQL Server Profiler 中,我们发现一个命令等于:
运行此块大约需要四秒使用
IQueryable
的代码。IQueryable 有一个名为
Expression
的属性,它存储一个树表达式,当我们在示例中使用result
时开始创建该表达式(称为延迟执行),最后表达式将转换为 SQL 查询以在数据库引擎上运行。Yes, both use deferred execution. Let's illustrate the difference using the SQL Server profiler....
When we run the following code:
In SQL Server profiler we find a command equal to:
It approximately takes 90 seconds to run that block of code against a WebLog table which has 1 million records.
So, all table records are loaded into memory as objects, and then with each .Where() it will be another filter in memory against these objects.
When we use
IQueryable
instead ofIEnumerable
in the above example (second line):In SQL Server profiler we find a command equal to:
It approximately takes four seconds to run this block of code using
IQueryable
.IQueryable has a property called
Expression
which stores a tree expression which starts being created when we used theresult
in our example (which is called deferred execution), and at the end this expression will be converted to an SQL query to run on the database engine.最上面的答案很好,但它没有提到解释两个接口“如何”不同的表达式树。基本上,有两组相同的 LINQ 扩展。
Where()
、Sum()
、Count()
、FirstOrDefault()
等都有两个版本:一种接受函数,另一种接受表达式。IEnumerable
版本签名为:Where(Func predicate)
IQueryable
版本签名为:Where(Expression> predicate)
您可能一直在使用以下两者那些没有意识到的,因为两者都使用相同的语法调用:
例如
Where(x => x.City == "")
适用于IEnumerable
和IQueryable
在
IEnumerable
集合上使用Where()
时,编译器会将编译后的函数传递给Where()
在
IQueryable
集合上使用Where()
时,编译器会将表达式树传递给Where()
。表达式树类似于代码的反射系统。编译器将您的代码转换为一种数据结构,以易于理解的格式描述您的代码的功能。为什么要为这个表达式树烦恼呢?我只想
Where()
过滤我的数据。主要原因是 EF 和 Linq2SQL ORM 都可以将表达式树直接转换为 SQL,这样您的代码执行速度会更快。
哦,这听起来像是免费的性能提升,在这种情况下我应该在各处使用
AsQueryable()
吗?不,
IQueryable
仅当底层数据提供程序可以使用它执行某些操作时才有用。将常规List
之类的内容转换为IQueryable
不会给您带来任何好处。The top answer is good but it doesn't mention expression trees which explain "how" the two interfaces differ. Basically, there are two identical sets of LINQ extensions.
Where()
,Sum()
,Count()
,FirstOrDefault()
, etc all have two versions: one that accepts functions and one that accepts expressions.The
IEnumerable
version signature is:Where(Func<Customer, bool> predicate)
The
IQueryable
version signature is:Where(Expression<Func<Customer, bool>> predicate)
You've probably been using both of those without realizing it because both are called using identical syntax:
e.g.
Where(x => x.City == "<City>")
works on bothIEnumerable
andIQueryable
When using
Where()
on anIEnumerable
collection, the compiler passes a compiled function toWhere()
When using
Where()
on anIQueryable
collection, the compiler passes an expression tree toWhere()
. An expression tree is like the reflection system but for code. The compiler converts your code into a data structure that describes what your code does in a format that's easily digestible.Why bother with this expression tree thing? I just want
Where()
to filter my data.The main reason is that both the EF and Linq2SQL ORMs can convert expression trees directly into SQL where your code will execute much faster.
Oh, that sounds like a free performance boost, should I use
AsQueryable()
all over the place in that case?No,
IQueryable
is only useful if the underlying data provider can do something with it. Converting something like a regularList
toIQueryable
will not give you any benefit.是的,两者都会为您提供延迟执行。
区别在于
IQueryable
是允许 LINQ-to-SQL(实际上是 LINQ.-to-anything)工作的接口。因此,如果您进一步优化IQueryable
,如果可能的话,该查询将在数据库中执行。对于
IEnumerable
情况,它将是 LINQ 到对象,这意味着与原始查询匹配的所有对象都必须从数据库加载到内存中。在代码中:
该代码将仅对选定的黄金客户执行 SQL。另一方面,以下代码将执行数据库中的原始查询,然后过滤掉内存中的非黄金客户:
这是一个非常重要的区别,并且正在处理
IQueryable
在许多情况下可以避免从数据库返回太多行。另一个主要例子是进行分页:如果您使用Take
< /a> 和跳过
IQueryable
,您只会得到请求的行数;在IEnumerable
上执行此操作将导致所有行都加载到内存中。Yes, both will give you deferred execution.
The difference is that
IQueryable<T>
is the interface that allows LINQ-to-SQL (LINQ.-to-anything really) to work. So if you further refine your query on anIQueryable<T>
, that query will be executed in the database, if possible.For the
IEnumerable<T>
case, it will be LINQ-to-object, meaning that all objects matching the original query will have to be loaded into memory from the database.In code:
That code will execute SQL to only select gold customers. The following code, on the other hand, will execute the original query in the database, then filtering out the non-gold customers in the memory:
This is quite an important difference, and working on
IQueryable<T>
can in many cases save you from returning too many rows from the database. Another prime example is doing paging: If you useTake
andSkip
onIQueryable
, you will only get the number of rows requested; doing that on anIEnumerable<T>
will cause all of your rows to be loaded in memory.