What is the difference between returning IQueryable<T>
vs. 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;
Will both be deferred execution and when should one be preferred over the other?
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.).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.
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.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.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#).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.