IEnumerable vs IQueryable - What's the difference

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 and IQueryable 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
40
An error has occurred. This application may no longer respond until reloaded. Reload x