tags / EF Core

Entity Framework Core Articles

How to Make Database Queries Easier to Debug

ORM query behaving differently than expected?

Look at the generated SQL.

In EF Core, you can inspect a query with:

var query = context.Orders
    .Where(x => x.Status == OrderStatus.Completed)
    .OrderByDescending(x => x.CreatedAt);

var sql = query.ToQueryString();
How to Make Database Queries Easier to Debug

Generated SQL helps you see:

  • Which columns are selected
  • Which joins were generated
  • Where filters are applied
  • How ordering works
  • Whether the query matches your assumptions

LINQ is convenient, but the database still executes SQL.

When a database query is slow or surprising, looking at the database query is often useful.

How to Update Rows Without Loading Them in EF Core

Need to update many rows in EF Core?

You don't always need to load them first.

Instead of:

var users = await context.Users
    .Where(x => !x.IsActive)
    .ToListAsync();

foreach (var user in users)
{
    user.Status = UserStatus.Disabled;
}

await context.SaveChangesAsync();

You can update matching rows directly:

await context.Users
    .Where(x => !x.IsActive)
    .ExecuteUpdateAsync(setters => setters
        .SetProperty(x => x.Status, UserStatus.Disabled));
How to Update Rows Without Loading Them in EF Core

ExecuteUpdateAsync() is useful when:

  • You need to update many rows
  • You don't need the entities in memory
  • You don't need change tracking
  • The update can be expressed as a database operation
  • You want to avoid unnecessary round trips and allocations

The update runs directly in the database.

If you don't need the entities, loading them before updating them is optional.

How to Avoid Loading an Entire Table into Memory

Need only active customers?

Filter them in the database.

Instead of:

var customers = await context.Customers.ToListAsync();

var activeCustomers = customers
    .Where(x => x.IsActive)
    .ToList();

Prefer:

var activeCustomers = await context.Customers
    .Where(x => x.IsActive)
    .ToListAsync();

The difference is where filtering happens.

How to Avoid Loading an Entire Table into Memory

The first approach:

  • Loads every row
  • Transfers every row
  • Stores every row in memory
  • Filters afterward

The second approach lets the database return the rows you requested.

If you need 100 customers from a table containing 1,000,000 rows, filtering before ToListAsync() tends to matter.

How to Speed Up Read-Only EF Core Queries

Reading data that you don't plan to update?

Consider AsNoTracking().

var products = await context.Products
    .AsNoTracking()
    .Where(x => x.IsActive)
    .ToListAsync();

By default, EF Core tracks entities so it can detect changes and persist them later.

For read-only scenarios, that tracking work might not be needed.

How to Speed Up Read-Only EF Core Queries

AsNoTracking() helps by:

  • Avoiding change tracking
  • Reducing tracking-related memory usage
  • Making the intent of the query explicit
  • Working well for API reads and reporting
  • Keeping read-only queries focused on reading

If you don't plan to change the entity, consider asking EF Core not to track changes.

How to Execute Code Before Every Request

Need to run logic for every incoming HTTP request?

Use ASP.NET Core middleware.

Common middleware scenarios:

  • Logging requests
  • Handling exceptions
  • Authentication
  • Authorization
  • Adding custom headers
  • Response compression

Middleware executes in the order you register it in the pipeline.

Each middleware can inspect the request, perform work, and pass execution to the next middleware.

How middleware works in .NET

How to Use SaveChangesAsync in .NET

Want asynchronous database writes in EF Core?

Use SaveChangesAsync() instead of SaveChanges().

How to Use SaveChangesAsync in .NET

Benefits:

  • Doesn't block the calling thread
  • Works better under load
  • Integrates with async/await
  • Recommended for ASP.NET Core applications
  • Available since EF Core was released

What other EF Core performance tips do you use?