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?
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
.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.
Reference Link
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.