An Include or ThenInclude call can be entirely inert: Entity Framework Core generates the exact same SQL with or without
it.
Why is this an issue?
Entity Framework Core resolves the navigation path of every Include/ThenInclude call and merges calls that resolve to the
same path into a single join. Repeating Include for a navigation that is already included, without adding a new ThenInclude
afterwards, generates identical SQL to removing the repeated call — it adds nothing but noise and can mislead a reader into thinking it changes what
is loaded.
Exceptions
The rule does not apply when:
- the repeated
Includecall re-anchors the chain before a differentThenInclude. Entity Framework Core has no syntax for attaching two differentThenIncludecontinuations to oneInclude, so repeating it is the idiomatic way to load two independent nested navigations or collections. - one of the calls applies a filter (through
Where,Skip,Take, or similar) that the other does not carry, regardless of which one is written first — removing the filtered call would change which rows are loaded.
How to fix it
Remove the Include (or ThenInclude) call that has no effect.
Code examples
Noncompliant code example
var students = await context.Students
.Include(s => s.Enrollments) // Noncompliant: "Enrollments" is already included below
.Include(s => s.Enrollments)
.ToListAsync();
Compliant solution
var students = await context.Students
.Include(s => s.Enrollments)
.ToListAsync();
This repeated Include is not redundant — it branches into two different ThenInclude calls:
var students = await context.Students
.Include(s => s.Enrollments).ThenInclude(e => e.Course)
.Include(s => s.Enrollments).ThenInclude(e => e.Student) // Compliant: re-anchors before a different ThenInclude
.ToListAsync();
Resources
Documentation
- Microsoft Learn - Loading related data - Eager loading
Related rules
- {rule:csharpsquid:S8733} - covers loading multiple sibling collections in a single query; this rule instead covers
Includecalls that add nothing to the query at all. - {rule:csharpsquid:S9023} - covers
Includecalls that silently drop real data, not just harmless no-ops.