gotchacsharpdotnetMajor
Entity Framework Core: N+1 query problem with lazy loading disabled
Viewed 0 times
N+1 queryeager loadingInclude ThenIncludelazy loading ef coreLINQ navigation property
Problem
When loading a list of entities and accessing a navigation property in a loop, EF Core issues one query per row by default (if lazy loading proxies are enabled) or throws a NullReferenceException (if disabled). Either way, related data is not loaded efficiently.
Solution
Use eager loading with Include() / ThenInclude() to load related data in a single query:
For projections that don't need the full entity, use Select to avoid loading unneeded columns:
// BAD — N+1 if lazy loading on, null ref if off
var orders = await db.Orders.ToListAsync();
foreach (var o in orders)
Console.WriteLine(o.Customer.Name); // extra query per row
// GOOD — single JOIN query
var orders = await db.Orders
.Include(o => o.Customer)
.ThenInclude(c => c.Address)
.ToListAsync();For projections that don't need the full entity, use Select to avoid loading unneeded columns:
var names = await db.Orders
.Select(o => new { o.Id, CustomerName = o.Customer.Name })
.ToListAsync();Why
EF Core translates LINQ to SQL and executes queries only when enumerated. Navigation properties are null until explicitly loaded. Lazy loading proxies intercept property access and issue additional queries per access — one per entity in the collection.
Gotchas
- Enabling lazy loading with UseLazyLoadingProxies is convenient but masks N+1 issues in development
- Split queries (.AsSplitQuery()) can help for multiple collection Includes but produce separate round trips
- Calling ToList() inside a loop materializes queries eagerly, potentially multiplying database calls
Revisions (0)
No revisions yet.