π ToList() is Slowing You Down: LINQ Execution Strategies Every .NET Dev Should Know

"It works⦠but it's slow."
If youβre building .NET apps with Entity Framework Core, the way you use ToList() might be silently sabotaging performance β especially on large datasets.
β‘ The Common Misuse of ToList()
var users = dbContext.Users.ToList();
var activeUsers = users.Where(u => u.IsActive).ToList(); // β Filters in memory
This looks fine β but it causes your app to:
Fetch all records from the database
Filter them in memory, not in SQL
Waste memory, increase latency, and break scalability
π LINQ Execution: Deferred vs Immediate
π Deferred Execution | π Immediate Execution |
Query is composed but not run until needed | Query runs instantly |
Methods: Where, Select, OrderBy | Methods: ToList, Count, First |
Enables SQL optimization via EF Core | Breaks SQL translation, forces in-memory |
π§ Real-world analogy:
Deferred execution is like preparing a shopping list. You donβt go shopping until you check out.
Immediate execution is like buying something every time you add it to the list.
π§ How .ToList() Breaks EF Coreβs Magic
Entity Framework Core uses IQueryable and expression trees to build SQL from LINQ.
Calling .ToList():
Ends that query-building chain
Materializes results into memory
Turns any further operations into pure C# LINQ, losing database optimization
Example:
// β Inefficient: Filters AFTER SQL
var users = dbContext.Users.ToList()
.Where(u => u.IsActive); // runs in memory
// β Efficient: Filters IN SQL
var users = dbContext.Users
.Where(u => u.IsActive)
.ToList(); // runs in SQL
β οΈ Bonus Trap: Beware .AsEnumerable()
var result = dbContext.Users
.AsEnumerable()
.Where(u => u.IsActive); // β Forces in-memory LINQ
π΄ Danger: .AsEnumerable() switches the context from IQueryable to IEnumerable. That means:
LINQ runs in memory, not SQL
You lose translation to SQL
You risk performance degradation or runtime exceptions (e.g., trying to translate non-translatable C# code)
Use it only when you know why you're switching to in-memory logic.
π Performance Comparison
Imagine querying a table with 100,000 records, needing only 10,000 active ones.
Query Style | SQL Query | Time | Memory Usage |
β ToList() then Where | SELECT * FROM Users | ~950ms | 120MB |
β Where() then ToList() | SELECT * FROM Users WHERE IsActive = 1 | ~120ms | 8MB |
π Visual Query Flow
[EF LINQ Query]
β
[Where clause on IQueryable]
β
[SQL Generated by EF Core]
β
[Filtered results returned]
π’ Keep queries composed with .Where, .Select, .OrderBy
π΄ Avoid terminating early with .ToList() unless absolutely necessary
β Best Practice Patterns
Practice | π₯ Verdict | Why |
Filtering after .ToList() | π΄ Bad | Runs in memory |
Filtering before .ToList() | π’ Good | Executes in SQL |
Projecting specific fields with .Select() | π’ Good | Reduces load |
Using .AsEnumerable() too early | π΄ Bad | Loses SQL translation |
Using .ToList() for disconnected logic | π‘ Okay | Safe when needed intentionally |
π‘ When Should You Use .ToList()?
β When you want to break from IQueryable for disconnected work
β Before using LINQ methods not supported in SQL (e.g., custom C# functions)
β For batch updates, logging, or JSON serialization
But always place it after all SQL-translateable filters.
π§ͺ Code Comparison
π΄ Bad:
var products = dbContext.Products.ToList()
.Where(p => p.Price > 1000);
π’ Good:
var products = dbContext.Products
.Where(p => p.Price > 1000)
.ToList();
π’ Even Better:
var productSummaries = dbContext.Products
.Where(p => p.Price > 1000)
.Select(p => new { p.Id, p.Name, p.Price })
.ToList();
π Want to Go Deeper?
Youβll love these upcoming blog posts:
π LINQ Gotchas in EF Core: Client-Eval Traps and Workarounds
π Batching vs Streaming Queries in .NET & EF Core
π The Hidden Cost of .Include(): When to Load Data Lazily
π― Final Thoughts
ToList() isnβt evil β itβs just eager.
In performance-sensitive apps, especially with large datasets or live databases:
β
Let EF Core do the heavy lifting
β
Think before you list
β
Always profile queries before pushing to production
π§Ύ TL;DR:
// β DO
dbContext.Users.Where(u => u.IsActive).ToList();
// β DON'T
dbContext.Users.ToList().Where(u => u.IsActive);
Subscribe to my newsletter
Read articles from Priya directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
