
Master All 7 EF Core Delete Behaviors in Under 5 Minutes
Explained with easy-to-follow illustrations and code samples
Understanding all delete behaviors in the framework you use daily at work or on personal projects can increase your confidence and productivity, especially when you need to move quickly.
Delete Behaviors are a widely used concept in relational databases like SQL Server, MySQL, Postgres, and Azure SQL. These behaviors define what should happen when there is a relationship between two or more entities, and one of them is deleted.
When working with Entity Framework Core, there are 7 Delete Behaviors provided as an enum in their SDK. They are the following:
- Cascade
- ClientCascade
- SetNull
- ClientSetNull
- NoAction
- Restrict
- ClientNoAction
By the end of this article, you will understand what each one does and when to choose them.
Cascade
The first type of delete behavior is called Cascade. It is the default behavior type for mandatory relationships.
To help you better understand the concept of delete behaviors, let’s embark on a short imaginary journey.
Picture yourself walking down the street with your loved one on a lovely evening. You both feel hungry and decide to eat at a restaurant. As you enter the restaurant, sit down, and open the menu, your engineer brain realizes that you are observing a one-to-many relationship between the restaurant and the different food items it offers on the menu.
You notice that the restaurant offers a variety of menu items, and each item is linked to that specific restaurant. Now, let’s get back to the idea of delete behaviors. Imagine that one day, while you’re walking down the same street, you come across the same restaurant, but you see that it is now out of business and the building will be demolished soon.
The restaurant had some delectable menu items, but without the staff and the chef who knew how to cook them, they would disappear along with the restaurant. From an engineering perspective, this relationship means that when the restaurant is deleted, all menu items should also be deleted. This is precisely what the Cascade delete behavior indicates.
In practice, the relationship between the restaurant and the menu items can be defined using two tables:

The delete behavior can be defined using the Fluent API like so:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<MenuItem>()
.HasOne(mi => mi.Restaurant)
.WithMany(r => r.MenuItems)
.HasForeignKey(mi => mi.RestaurantId)
.OnDelete(DeleteBehavior.Cascade);
}
Unfortunately, not all databases support the Cascade delete behavior. For this reason, you can use the ClientCascade delete behavior instead, which will simulate a cascade delete inside your application by fetching all related entities and deleting them as well.
SetNull
Next up, we have the SetNull behavior. This is the default behavior for database entities that can live without a parent.
Consider the example of a public library where books are available for loan to anyone with a library card. In this case, the books have an optional owner, which is the person who borrows the book using their library card.
Once the borrower returns the book to the library, it becomes available for loan again to another person and has no specific owner until the next person borrows it.
In practice, this relationship could be defined as a one-to-many relationship between Users and Books.

Whenever a User is deleted, all of his borrowed books will have the borrowedBy” Foreign Key set to null.
In order to define this relationship in EF Core, you will need to use the Fluent API:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Book>()
.HasOne(b => b.User)
.WithMany(u => u.Books)
.HasForeignKey(b => b.BorrowedBy)
.OnDelete(DeleteBehavior.SetNull);
}
To avoid an exception being thrown by EF Core when trying to set the value of a foreign key to null, ensure that the BorrowedBy variable is set to nullable.
Unfortunately, just like the Cascade delete behavior, very few databases actually support the SetNull behavior. Instead, use the ClientSetNull to simulate the process inside your code by fetching all related entities and automatically setting their foreign key value to null.
Restrict
The last behavior is called Restrict. This type of delete behavior prevents the entity from being deleted if it has linked entities to it.
Imagine you're running an online shop with a wide range of products belonging to various categories. Each product is linked to a specific category.
Inside your application there is also the ability to delete a certain category from the admin panel. In order to prevent unintended deletion of products, you can prevent the deletion of the category if it has products linked to it.
The database structure would include a one-to-many relationship between a Category and Products

In order to define the Restrict delete behavior, use the Fluent API:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>()
.HasOne(p => p.Category)
.WithMany(c => c.Products)
.HasForeignKey(p => p.CategoryId)
.OnDelete(DeleteBehavior.Restrict);
}
In practice, most databases have support for this behavior. Otherwise, you can use NoAction or ClientNoAction, which do the exact same thing*.
Key Takeaways:
- Cascade will also delete all linked entities.
- SetNull will set all linked foreign keys to null.
- Restrict will prevent deleting an entity if it has linked entities.
- ClientCascade, ClientSetNull, and ClientRestrict simulate the same process inside your code in case the database engine does not support these operations.
- *NoAction is the same as Restrict, except when using PostgreSQL.
Thank you so much for reading this article about .NET! 💻❤️
I have an entire series of articles dedicated to .NET, which you can find here:
Also, If you’d like to be up to date and read more articles like this one, be sure to follow me!
See you in the next one! 👋
Credits:
Some images from this article were drawn by artists on Flaticon, give them some love 💖!
- Database Icon — Made by Srip on Flaticon
- Delete Icon — Made by Pixel Perfect on Flaticon