Pebellslearn by building
0%
RoadmapsMatrixCoursesSandboxSign in
Object Relational Mapping  ›  Capstone Project

Lazy, Eager and Explicit Loading

Lazy, Eager, Explicit Loading 15 minRelated entities are not loaded automatically: eager loading fetches them with Include, explicit loading fetches them on request, and lazy loading fetches them on first access at the risk of many small queries.

Lazy, Eager and Explicit Loading

ReadingRoom's members page loads members, then shows each member's loans. On your laptop with three members it is instant. In production with fifty it is slow, and the log shows fifty-one queries. The cause is how related data was loaded.

The rule

Related data is never free: include it, load it, or pay per access.

Member has a navigation property to its loans:

public class Member
{
    public int Id { get; set; }
    public string Name { get; set; } = "";
    public List<Loan> Loans { get; set; } = [];
}

Loading db.Members does not fill Loans. You choose one of three strategies:

Eager — ask for it up front with Include:

var members = await db.Members
    .Include(m => m.Loans.Where(l => l.ReturnedAt == null))
    .ToListAsync();

Explicit — load it later, on purpose, for one entity:

var member = await db.Members.FindAsync(5);
await db.Entry(member!).Collection(m => m.Loans).LoadAsync();

Lazy — load it automatically the first time the property is read. It is off by default; you opt in with the Microsoft.EntityFrameworkCore.Proxies package, UseLazyLoadingProxies(), and virtual navigation properties.

Lazy loading is convenient and dangerous. A loop over 50 members that reads member.Loans fires one query for the members and then one per member: the N+1 problem. Each query is quick; together they are slow.

For multiple collections, Include can produce huge joined results; .AsSplitQuery() fetches each collection in its own query instead. And when a page only needs a few columns, a Select projection often beats loading whole entities.

The shortcut

Before a query, ask "will I use the related data for every row, some rows, or by surprise?" Every row → eager (Include). Some rows → explicit. "By surprise" is lazy — and usually a bug waiting to happen.

Fixing the members pageStep 1 of 4
  1. Count the queries

    One for members, then one per member for loans: 1 + 50 = 51.

The trap: seeing an empty Loans list and concluding the member has no loans. Without Include or a load, EF simply never fetched them.

Drills

Answer fast — trust the rule.

quick drill

Which method eagerly loads a member's loans in the same query?

quick drill

Listing 20 members with lazy loading, the page reads each member's Loans. How many queries run?

quick drill

What does lazy loading require in EF Core?

quick drill

A librarian expands one member out of a list to see their loans. Which strategy fits best?

Remember

  • Related data is never free: include it, load it, or pay per access.
  • Every row → Include; some rows → explicit LoadAsync; lazy invites N+1.
  • An empty navigation often means "not loaded", not "none".

Practice — level up

0/1 solved

Write your answer, then compare it with a rubric and a model answer.

ExplainFix the N+1 page

ReadingRoom's members page shows 50 members with their current loans, and the log shows 51 SQL queries. Explain what causes this, which loading strategy fixes it and how, and when explicit loading would be the better choice.