Let's start slowly: IQueryable
extends IEnumerable
. What does that mean? Well, whatever you want to do with IEnumerable
you can also do with IQueryable
. So there have to be some conceptual differences between does two.
Small disclaimer: When I speak of IEnumerable
or IQueryable
I refer to the generic variation. But most of the facts hold true for the non-generic version which was used prior to .NET 2.
First of all we can see they both life in totally different namespaces:
IEnumerable
-System.Collections.Generic
IQueryable
-System.Linq
So we see there is a big difference. IEnumerable
is used for collections and IQueryable
is used for querying data. But both have a common behavior: They are forward collections
. Both types are not immediately evaluated. One has to materialize them for example via ToList()
.
IQueryable
provides mainly two new properties:
IQueryProvider
- Executes an expression against something else (e.g. LINQ to SQL - translate the expression to valid SQL)Expression
- This can be a whole expression tree (e.g. predicates, value selectors, ...)
With these two concepts you can build a whole complex model and translate it to the underlying connection (e.g. LINQ to XML / LINQ to SQL, ...). Simplified IEnumerable
only accepts some delegate. You can see this very clearly if you for example look at the definition of Where
:
IEnumerable
version signature is:Where(Func<T, bool> predicate)
IQueryable
version signature is:Where(Expression<Func<T, bool>> predicate)
What happens if we use IEnumerable
for querying data against the database
Let's have a look at the following code:
IEnumerable<Employee> employees = GetEmployees();
employees.Where(e => e.Workload > 50).ToList();
And the same example but with a IQuerayable
:
IQueryable<Employee> employees = GetEmployees();
employees.Where(e => e.Workload > 50).ToList();
Let's assume that GetEmployees
gives us a DbContext
which goes down to the SQL-Server.
In the first example all Employees are loaded to the client and afterwards the predicate is executed on them.
In the second example all Employees are filtered on the server and only the matched ones are returned to the client.
If your data set is big enough this makes a huge difference. Another example would be Pagination. Skip
and Take
will not work with IEnumerable
in connection with a database. You would retrieve all objects into memory and execute Skip
and Take
afterwards (on the client).
Summary
Here is a small overview:
- Both
IEnumerable
andIQueryable
are forward collections - they don't get materialized right away - Querying data from the database
IEnumerable
will load the data into memory in a filter afterward on the client - Querying data from the database
IQueryable
will filter first and afterward send the filtered data to the client IQueryable
is suitable for querying data from out-memory- There can be scenarios where the underlying query provider can't translate your expression to something meaningful then you have to switch to
IEnumerable