Introduction

When working with Entity Framework Core (EF Core), performance is one of the most important aspects of building scalable and efficient applications. One of the most common performance issues developers face is the N+1 Query Problem.

The N+1 query problem in EF Core can silently slow down your application by executing multiple unnecessary database queries instead of a single optimized query. If not handled properly, it can lead to serious performance bottlenecks, especially in large-scale applications.

In this article, we will explain what the EF Core N+1 query problem is in simple words, how it happens, and most importantly, how to fix it with practical examples and best practices.

What is the N+1 Query Problem?

The N+1 query problem occurs when your application executes one query to fetch data (the “1”) and then executes additional queries (the “N”) for each related record.

In simple words:

This results in too many database calls, which reduces performance.

Example of N+1 Problem in EF Core

Consider two entities:

C#
public class Order
{
    public int Id { get; set; }
    public string CustomerName { get; set; }
    public List<OrderItem> Items { get; set; }
}

public class OrderItem
{
    public int Id { get; set; }
    public string ProductName { get; set; }
}

Problematic Code

C#
var orders = dbContext.Orders.ToList();

foreach (var order in orders)
{
    var items = order.Items; // Triggers query for each order
}

What Happens Behind the Scenes

This creates multiple database calls.

Why N+1 Problem is Dangerous

How to Fix N+1 Query Problem in EF Core

Now let’s explore the solutions.

1. Use Eager Loading (Include)

Eager loading fetches related data in a single query.

Example

C#
var orders = dbContext.Orders
    .Include(o => o.Items)
    .ToList();

Benefit

2. Use ThenInclude for Nested Data

For deeper relationships, use ThenInclude.

C#
var orders = dbContext.Orders
    .Include(o => o.Items)
    .ThenInclude(i => i.Product)
    .ToList();

3. Use Select Projection (Best Practice)

Instead of loading full entities, select only required data.

Example

C#
var orders = dbContext.Orders
    .Select(o => new
    {
        o.Id,
        o.CustomerName,
        Items = o.Items.Select(i => i.ProductName).ToList()
    })
    .ToList();

Benefit

4. Disable Lazy Loading (If Enabled)

Lazy loading often causes N+1 issues.

Disable Lazy Loading

C#
optionsBuilder.UseLazyLoadingProxies(false);

Why?

Lazy loading loads data only when accessed, which can trigger multiple queries.

5. Use Explicit Loading Carefully

Explicit loading allows controlled loading of related data.

C#
dbContext.Entry(order)
    .Collection(o => o.Items)
    .Load();

Use it when needed, but avoid inside loops.

6. Use AsNoTracking for Read-Only Queries

C#
var orders = dbContext.Orders
    .Include(o => o.Items)
    .AsNoTracking()
    .ToList();

Benefit

7. Use Split Queries (Advanced)

EF Core allows splitting queries to improve performance.

C#
var orders = dbContext.Orders
    .Include(o => o.Items)
    .AsSplitQuery()
    .ToList();

Difference Between Lazy, Eager, and Explicit Loading

FeatureLazy LoadingEager LoadingExplicit Loading
QueriesMultipleSingleControlled
PerformancePoor (N+1 risk)GoodModerate
Use CaseSmall dataMost casesSpecial scenarios

Real-World Example

In an e-commerce system:

This directly impacts user experience.

How to Detect N+1 Problem

Common Mistakes to Avoid

1. Using Lazy Loading in Loops

Leads to multiple queries.

2. Fetching Unnecessary Data

Use projection instead.

3. Ignoring Query Logs

Always monitor queries.

Best Practices to Avoid N+1 Problem

Summary

The N+1 query problem in EF Core is a common performance issue caused by executing multiple unnecessary database queries. By using techniques like eager loading, projection, and disabling lazy loading, you can significantly improve performance. Understanding and fixing the N+1 problem is essential for building scalable, efficient, and high-performance applications using Entity Framework Core.