When working with data in C#, especially when using LINQ or Entity Framework, developers often come across two interfaces: IEnumerable
and IQueryable
. Although both allow iteration over collections, they have crucial differences especially regarding performance and execution context.
This article will break it all down in plain English, using analogies, real-world examples, and relevant code blocks.
Feature | IEnumerable |
IQueryable |
---|---|---|
Namespace | System.Collections |
System.Linq |
Execution | In-memory | Out-of-memory (like database) |
Filtering | After data is loaded | Translates filtering to data source (e.g., SQL) |
Deferred Execution | ✅ Yes | ✅ Yes |
Best Used With | Local collections (Lists, Arrays, etc.) | Remote data (Entity Framework, LINQ to SQL) |
🎯 High-Level Concept
IEnumerable
is like fetching all books from a library to your house and then picking the ones you like.
IQueryable
is like calling the library and asking them to only send you books published after 2010.
🏗️ Deep Dive: IEnumerable
✅ Definition
IEnumerable is an interface that allows iteration over a collection in memory.
public interface IEnumerable
{
IEnumerator GetEnumerator();
}
📘 Example Use Case
List<string> names = new List<string> { "Alice", "Bob", "Charlie" };
IEnumerable<string> filteredNames = names.Where(n => n.StartsWith("A"));
foreach (var name in filteredNames)
{
Console.WriteLine(name); // Output: Alice
}
The filtering (Where) happens after the list is loaded in memory.
Great for working with already-fetched data like arrays or lists.
🌐 Deep Dive: IQueryable
✅ Definition
IQueryable
extends IEnumerable
and is designed for querying remote data sources like databases. It allows LINQ queries to be translated to SQL and executed on the server.
public interface IQueryable : IEnumerable
{
Type ElementType { get; }
Expression Expression { get; }
IQueryProvider Provider { get; }
}
📘 Example Use Case (Entity Framework)
IQueryable<User> users = dbContext.Users.Where(u => u.Age > 30);
No data is fetched yet.
When enumerated (e.g., with .ToList()), it gets translated into:
SELECT * FROM Users WHERE Age > 30
- Only the relevant data is pulled from the database much more efficient for large datasets.
⚖️ IEnumerable vs IQueryable : Real-World Analogy
🍎 Grocery Shopping Analogy
Scenario | IEnumerable |
IQueryable |
---|---|---|
You go to the store and bring home all the fruits, then sort them. | ✅ | ❌ |
You call ahead and ask them to only pack fruits under \$5, then you pick up the box. | ❌ | ✅ |
📦 Under the Hood: Execution Flow
IEnumerable:
List<Product> products = db.Products.ToList(); // Data loaded into memory
var cheapProducts = products.Where(p => p.Price < 50); // Filtering in memory
Query is translated to SQL.
Only required rows are returned from the database, better for performance.
💥 Performance Impact
Example
Imagine a Products
table with 1 million rows.
// IEnumerable - Bad!
List<Product> allProducts = db.Products.ToList(); // Loads ALL rows
var filtered = allProducts.Where(p => p.Price > 1000); // Filters in memory
- ❌ Loads a ton of unnecessary data
// IQueryable - Good!
var filtered = db.Products.Where(p => p.Price > 1000).ToList(); // SQL does the filtering
✅ Only needed rows come across the network
🛠 When to Use What?
Use Case | Use IEnumerable
|
Use IQueryable
|
---|---|---|
Working with in-memory collections | ✅ Yes | ❌ No |
Querying large datasets from database | ❌ No | ✅ Yes |
LINQ to Objects | ✅ | ❌ |
Entity Framework / LINQ to SQL | ❌ | ✅ |
You want SQL optimization (e.g., joins, WHERE) | ❌ | ✅ |
🧩 Bonus: Mixing Both
You can combine both interfaces:
// IQueryable: query to DB
var query = db.Users.Where(u => u.IsActive);
// IEnumerable: further filter in memory
var activeAdmins = query.ToList().Where(u => u.Role == "Admin");
✅ Summary
Criteria | IEnumerable |
IQueryable |
---|---|---|
Execution | In-memory | Database or remote query |
Performance | Slower for large datasets | Faster, optimized for data queries |
Best For | Collections already in memory | Querying databases |
🧠 Final Thought
- If you’re working with data that’s already in memory, go with IEnumerable.
- If you’re pulling from a database, use IQueryable to avoid performance issues.
LinkedIn Account
: LinkedIn
Twitter Account
: Twitter
Credit: Graphics sourced from Yohan's Blog