IEnumerable vs IQuerable

Introduction

IEnumerable and IQuerable both are the interfaces for .Net collections. And IQuerable inherits the IEnumerable interfaces, in other words all the functionality implemented by IQuerable also can be implemented. So the question here is the difference and why the Microsoft provided the IQuerable interface.

Differences

The IEnumerable is used to iterate a read-only collection. It has only one method, GetEnumerator(), that allows you to iterate the read-only collection using a foreach loop. It only iterates in the forward direction.

In the Entity Framework solution (that we create here as a sample), if your data loads in a collection then you can easily see the difference between both of these, it effects the performance. First we will create a sample Entity Framework sample here. Here is the code of Program.cs.

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Data.Entity;  
  4. using System.Data.Entity.ModelConfiguration.Conventions;  
  5. using System.Linq;  
  6. using System.Text;  
  7. using System.Threading.Tasks;  
  8.    
  9. namespace ManyToManyEfSample2  
  10. {  
  11.     class Program  
  12.     {  
  13.         static void Main(string[] args)  
  14.         {  
  15.             Database.SetInitializer<SchoolContext>(null);  
  16.             using (SchoolContext db = new SchoolContext())  
  17.             {  
  18.                 Course CS = new Course();  
  19.                 Course IT = new Course();  
  20.                 CS.Title = "Computer Science";  
  21.                 IT.Title = "Information Technology";  
  22.    
  23.                 db.Courses.Add(CS);  
  24.                 db.Courses.Add(IT);  
  25.    
  26.                 Person P1 = new Person();  
  27.                 P1.FirstName = "Vivek";  
  28.                 P1.LastName = "Tripathi";  
  29.                 P1.Courses.Add(CS);  
  30.                 P1.Courses.Add(IT);  
  31.    
  32.                 db.People.Add(P1);  
  33.                 db.SaveChanges();  
  34.             }  
  35.         }  
  36.     }  
  37.    
  38.     public class Person  
  39.     {  
  40.         public int PersonId { getset; }  
  41.         public string FirstName { getset; }  
  42.         public string LastName { getset; }  
  43.    
  44.         public virtual ICollection<Course> Courses { getset; }  
  45.    
  46.         public Person()  
  47.         {  
  48.             Courses = new HashSet<Course>();  
  49.         }  
  50.     }  
  51.    
  52.     public class Course  
  53.     {  
  54.         public int CourseId { getset; }  
  55.         public string Title { getset; }  
  56.    
  57.         public virtual ICollection<Person> Students { getset; }  
  58.    
  59.         public Course()  
  60.         {  
  61.             Students = new HashSet<Person>();  
  62.         }  
  63.     }  
  64.    
  65.     public class SchoolContext : DbContext  
  66.     {  
  67.         public DbSet<Course> Courses { getset; }  
  68.         public DbSet<Person> People { getset; }  
  69.    
  70.         public SchoolContext()  
  71.             : base("ConnString")  
  72.         {  
  73.         }  
  74.    
  75.         protected override void OnModelCreating(DbModelBuilder modelBuilder)  
  76.         {  
  77.             modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();  
  78.             modelBuilder.Entity<Course>().  
  79.                 HasMany(c => c.Students).  
  80.                 WithMany(p => p.Courses).  
  81.                 Map(  
  82.                     m =>  
  83.                     {  
  84.                         m.MapLeftKey("CourseId");  
  85.                         m.MapRightKey("PersonId");  
  86.                         m.ToTable("PersonCourses");  
  87.                     });  
  88.    
  89.         }  
  90.     }  
  91. }  
Now when fetching the data from the Person Table we will see the difference between the two .Net Collections.
  1. using (SchoolContext db = new SchoolContext())  
  2. {  
  3.    IEnumerable<Person> P = db.People;  
  4.    IEnumerable<Person> P2 = P.Where(x => x.PersonId == 1).ToList<Person>();  
  5. }  
In the block, x => x.PersonId == 1 is an anonymous method that can be executed like any other method. And the “Where” will execute the method once for each person, yielding values for which the method returned true. So you can say all the processing (anonymous function) call happened on the client side.

If we run this code we will see the query on the profiler.

query on profiler

So it's clear from the profiler that when using the IEnumerable, we fetch all the data from the DB and the filter criteria is implemented on the client side.

When changing the code it will be like this:
  1. IQueryable<Person> P = db.People;   
  2. var P3 = P.Where(x => x.PersonId == 1).ToList();  
In the second block, x => x.PersonId == 1 is an expression tree(), that can be thought of as "is the 'PersonId' property == 1".

You can see the query in the following window. The filter criteria (where clause) is applied in the DB Query. So, performance-wise the Iquerable is much more important.

Performance

Conclusion
  • If you create IQueryable, then the query may be converted to SQL and will run on the database server.

  • If you create IEnumerable, then all rows will be pulled into memory as objects before running the query.

So in short we can say that IEnumerable is great for working with in-memory collections, but IQueryable allows for a remote data source such as a database or web service.