IEnumerable vs IQueryable
LINQ
LINQ to Entities, LINQ to SQL and LINQ to Dataset
LINQ to Entities vs LINQ to Objects
Summary:
- LINQ-to-Objects is a set of extension methods on
IEnumerable<T>that allow you to perform in-memory query operations on arbitrary sequences of objects. - LINQ-to-Entities is a LINQ provider that has a set of extension methods on
IQueryable<T>. The methods build up an expression tree (which is why delegates are actually passed as Expression<>s), and the provider will build up a SQL query based on its parsing of that expression tree.
IEnumerable vs IQueryable
Looking at the source code, we can see IQueryable extends IEnumerable:
public interface IQueryable : IEnumerable
{
Type ElementType { get; }
Expression Expression { get; }
IQueryProvider Provider { get; }
}
Consider a DbContext:
public class MyDbContext : DbContext
{
public DbSet<Employee> Employee { get; set; }
}
Abstract class DbSet implements both IQueryable and IEnumerable.
Let’s do some experiments.
Use IEnumerable
Here we access to DbSet as an IEnumerable
IEnumerable<Employee> enumerable = dbContext.Employee;
enumerable.Count();
To show generated SQL query to console, you can call DbContextOptionsBuilder.UseLoggerFactory() when create DbContext.
Or use any SQL profiler, we can see the SQL query is like:
SELECT "e"."Id", "e"."IsActive", "e"."Name"
FROM "Employee" AS "e"
We can see with this query, the data is fetched all rows to memory first, then the Count() is applied on in-memory data.
Use IQueryable
IQueryable<Employee> queryable = dbContext.Employee;
queryable.Count();
Print log or use any SQL profiler, we can see the SQL query is like:
SELECT COUNT(*)
FROM "Employee" AS "e"
We can see with this query, only the count number is fetched and add to memory, not all data.
The Count() is not applied to in-memory data, but combined into single query to be executed in server.
Summary
In the case of IEnumerable, the code line IEnumerable<Employee> enumerable = dbContext.Employee creates an enumerable and forces the later query (Count()) to perform as LINQ-to-Objects (in-memory LINQ).
In the case of IQueryable, we actually use LINQ-to-Entities via IQueryable, and it translates into the final query to be executed in server.
It’s clearly that in this example, IQueryable has better performance than IEnumerable, but not all methods are supported in this smart ways.
References: