Performance C# active any

Avoid eager-loading multiple collection navigations in one query

perf-csharp-003

Intent

Loading several collection navigations in one query can multiply rows and transfer large duplicated result sets.

Applicability

Applies when the diff adds or changes EF Core queries with Include chains over collection navigations. Return unknown if the query shape or navigation cardinality is not visible enough to tell whether multiple collection includes are involved.

What to inspect

EF queries using .Include() and .ThenInclude(), the entity model for whether the included navigations are collections, and any projection that limits the shape of the loaded result.

Pass criteria

The query loads at most one collection navigation from the root entity, or it projects only the needed related data instead of eagerly loading multiple collections into one result set.

Fail criteria

The diff adds a single EF query that eagerly loads multiple collection navigations from the same root graph, with no visible projection or other shaping to avoid a large multiplied result.

Do not flag

Do not flag includes of reference navigations only. Do not flag a single collection include when no second collection is joined into the same query. Do not flag code that already projects to a limited result shape instead of materializing the full graph.

Confidence guidance

HIGH when the diff clearly shows multiple collection Include paths on one query. MEDIUM when multiple includes are visible, and nearby entity definitions strongly imply they are collections. LOW when the include chain is visible, but repository context is too weak to confirm navigation cardinality.

Remediation

Replace the broad eager load with a projection that fetches only the related data the caller actually needs.

Pass example

var orders = await context.Orders
    .Select(o => new
    {
        o.Id,
        CustomerName = o.Customer.Name,
        ItemCount = o.Items.Count
    })
    .ToListAsync();

Fail example

var orders = await context.Orders
    .Include(o => o.Items)
    .Include(o => o.Payments)
    .ToListAsync();

Sources

  • Vlad Mihalcea's blog + EF Core performance docs article