.NETMedium
How do you fix the N+1 query problem in EF Core?
The trap:
var orders = await db.Orders.ToListAsync(); // 1 query
foreach (var o in orders)
Console.WriteLine(o.Customer.Email); // 100 lazy-load queries
Three fixes — pick by query shape:
1. Include — for 1-to-1 or small 1-to-many:
var orders = await db.Orders
.Include(o => o.Customer)
.ToListAsync();
One JOIN, one round-trip.
2. Split queries — when including multiple collections:
var orders = await db.Orders
.Include(o => o.Customer)
.Include(o => o.LineItems).ThenInclude(li => li.Product)
.AsSplitQuery()
.ToListAsync();
Multiple Include on collections causes a Cartesian product (rows ✕ rows). AsSplitQuery runs separate queries and stitches them in memory.
3. Projection — usually the right answer:
var rows = await db.Orders
.Select(o => new OrderListItem(o.Id, o.Customer.Name, o.LineItems.Count))
.ToListAsync();
EF generates one efficient SQL with only the columns you need. No tracking, no Cartesian, no surprise lazy-loads.
Detect in dev: enable EF Core SQL logging and look for repeated identical SELECT shapes. In tests, count queries with MiniProfiler and assert an upper bound.