Entity Framework
DbSet
Database
Data Deletion
C#

How should I remove all elements in a DbSet?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Removing all rows from a DbSet sounds simple, but the best approach depends on your Entity Framework version and what "remove" really means for your application. Sometimes you want tracked entity deletion with cascade behavior and domain hooks. Other times you just want the fastest possible SQL DELETE.

The important decision is whether Entity Framework should load entities into the change tracker first. If not, use a set-based delete. If yes, use RemoveRange.

Best Option in Modern EF Core: ExecuteDelete

If you are using EF Core 7 or later, the cleanest solution is usually ExecuteDeleteAsync():

csharp
using Microsoft.EntityFrameworkCore;

await context.Orders.ExecuteDeleteAsync();

This translates to a single SQL DELETE statement and does not load every row into memory. It is usually the right answer when:

  • you do not need each entity tracked
  • you do not need per-entity business logic in application code
  • you want database-side execution and better performance

Because the delete happens directly in the database, it is dramatically more efficient than fetching thousands of rows and removing them one by one.

Use RemoveRange When Tracking Matters

If you need EF to track the deletions, or you rely on client-side logic around entity removal, use RemoveRange:

csharp
1using Microsoft.EntityFrameworkCore;
2
3var customers = await context.Customers.ToListAsync();
4context.Customers.RemoveRange(customers);
5await context.SaveChangesAsync();

This works in older EF Core versions and in scenarios where entity instances must pass through the normal change tracker pipeline.

The downside is obvious: every row is first materialized into memory. That can be expensive for large tables.

When Raw SQL or TRUNCATE Makes Sense

Sometimes you are not really doing "entity deletion" at all. You are clearing a table.

In that case, raw SQL may be appropriate:

csharp
await context.Database.ExecuteSqlRawAsync("DELETE FROM [Logs]");

Or, if your database allows it and the table relationships permit it:

csharp
await context.Database.ExecuteSqlRawAsync("TRUNCATE TABLE [Logs]");

TRUNCATE is usually faster than DELETE, but it comes with important differences:

  • it may reset identity values
  • it can be blocked by foreign key constraints
  • it bypasses normal EF change tracking entirely

So use it only when the database semantics match what you need.

Choosing the Right Approach

A practical rule of thumb looks like this:

  • use ExecuteDeleteAsync() for large set-based deletes in EF Core 7+
  • use RemoveRange() when the entities need to be loaded and tracked
  • use raw SQL or TRUNCATE when you are performing a database maintenance style operation

Here is a small comparison:

csharp
1// Fast, server-side, no tracking
2await context.Sessions.ExecuteDeleteAsync();
3
4// Slower, tracked, loads rows first
5context.Sessions.RemoveRange(await context.Sessions.ToListAsync());
6await context.SaveChangesAsync();

The fastest option is not always the safest one if your code depends on the entity lifecycle.

Consider Relationships and Side Effects

Before clearing a DbSet, think about foreign keys, cascade delete behavior, and other tables that depend on the rows.

For example, deleting all Orders may fail or behave differently depending on:

  • required child rows
  • cascade rules in the database
  • soft-delete conventions
  • triggers or auditing tables

This is why the correct answer is never just "call delete on everything." You need to understand what the database is supposed to do when those rows disappear.

Common Pitfalls

  • Loading an entire large table into memory when a set-based delete would do the job.
  • Using raw SQL or TRUNCATE and then forgetting the EF change tracker still has stale entities in memory.
  • Assuming TRUNCATE is just a faster DELETE. It has different semantics.
  • Clearing a DbSet without considering foreign keys or cascade behavior.
  • Choosing RemoveRange in a hot path where performance matters and there is no need for tracking.

Summary

  • The best modern solution is often ExecuteDeleteAsync() in EF Core 7+.
  • Use RemoveRange() when you genuinely need tracked entity deletion.
  • Use raw SQL or TRUNCATE only when database-level behavior is acceptable.
  • Always consider relationships, cascade rules, and the EF change tracker.
  • "Remove all rows" is easy to say, but the right implementation depends on whether you want entity semantics or pure database semantics.

Course illustration
Course illustration

All Rights Reserved.