Skip to content

C# IEnumerable vs IQueryable — Complete Guide

DodaTech Updated 2026-06-24 2 min read

In this tutorial, you'll learn about C# IEnumerable vs IQueryable. We cover key concepts, practical examples, and best practices.

You query a database with LINQ, filter with .Where(), and it returns all rows before filtering. The query ran in memory instead of SQL. You used IEnumerable<T> where IQueryable<T> was needed — or vice versa. Choosing the wrong interface impacts performance and correctness.

Wrong

// IEnumerable — filtering happens in memory
IEnumerable<Order> orders = db.Orders;
var bigOrders = orders.Where(o => o.Total > 1000).ToList();

Output: SQL query is SELECT * FROM Orders — all rows loaded into memory. Filtering happens client-side.

// IQueryable — filtering translates to SQL
IQueryable<Order> orders = db.Orders;
var bigOrders = orders.Where(o => o.Total > 1000).ToList();

Output: SQL query is SELECT * FROM Orders WHERE Total > 1000 — filtering happens in the database. Only matching rows are transferred.

The key difference:

Aspect IEnumerable<T> IQueryable<T>
Execution In-memory (LINQ to Objects) Deferred, composable (LINQ to SQL)
Filtering Client-side after data load Server-side as SQL WHERE
Performance Loads all data first Only loads needed rows
Use with Collections, arrays, in-memory data EF Core, remote data sources

Prevention

  • Use IQueryable<T> for database queries to ensure server-side evaluation.
  • Use IEnumerable<T> for in-memory collections (arrays, lists).
  • Be aware that calling ToList(), ToArray(), or AsEnumerable() breaks the IQueryable chain.
  • Use AsQueryable() only when you need query composition on in-memory data.
  • Check the generated SQL (with EF Core logging) to verify server-side evaluation.
  • Return IQueryable<T> from repository methods to allow query composition.

Common Mistakes with ienumerable vs iqueryable

  1. Misunderstanding that String is [Char] with poor performance for large text operations
  2. Using foldl instead of foldl' causing stack overflow on large lists
  3. Forgetting deriving (Show, Eq) on custom data types needed for debugging

These mistakes appear frequently in real-world CSHARP code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.

Practice Exercise

Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.

This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.

FAQ

How do I check if my query runs as SQL or in memory?

Enable EF Core logging: optionsBuilder.LogTo(Console.WriteLine). The log shows the SQL query. If you see SELECT * without a WHERE, the filter applied in memory. You can also check the type at runtime — IQueryable vs IEnumerable.

Can I convert between IEnumerable and IQueryable?

Yes. .AsQueryable() converts IEnumerable to IQueryable (but filtering still runs in memory). .AsEnumerable() breaks the IQueryable chain — subsequent operations run in memory. Use these conversions deliberately.

Why does my query work locally but timeout in production?

You likely used IEnumerable for a database query, loading all rows into memory. Works with 100 test rows; crashes with 1M production rows. Always use IQueryable for database queries and verify the generated SQL.

This pattern is critical in DodaTech's data layer — IQueryable ensures efficient database queries across all products. For more EF Core tips, visit DodaTech.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro