Cascade Delete in Entity Framework Core

Entity Framework Core Cascade Delete is one of the Referential actions. These actions specify what to do with the related rows when we delete the parent row. We can configure these actions in the database and in the EF core (Client). The options available to use are Delete the related rows (Cascade / ClientCascade), Update its Foreign Key to NULL (SetNull / ClientSetNull) or do nothing (Restrict/ NoAction / ClientNoAction). We setup delete behavior between entities using the FluentAPI OnDelete method.

The ClientCascade, NoAction & ClientNoAction are added in EF Core 3.0. If you were using Restrict then code will break. You should change it to ClientNoAction

Relationships Recap

The entities participating in the relationship can be either Principal entity (parent entity) or Dependent Entity (child entity). The principal entity is the one that can exist on its own. The Dependent Entity depends on Principal Entity.

For Example, consider the relationship between Employee and Department entity. The Department entity is the Principal entity as it does not need an Employee entity. But the Employees must belong to a department. Hence Employee entity is a Dependent Entity.

The Foreign Key is the glue between Principal Entity and its Dependent Entity. It can be either Required or Optional. If the Foreign Key is optional, then we can store the NULL value in it.

The database should not allow us to delete the parent record when it has a child record. it must keep the integrity of the data. It does so by using Referential actions. They are the actions that the database will take when we delete a parent record.

For Example, in an SQL Server database defines the four Referential actions. They are ON DELETE CASCADE, ON DELETE SET NULL, ON DELETE NO ACTION & ON DELETE SET DEFAULT

When we delete a parent record, the database will take one of the following actions based on the Referential actions.

  1. ON DELETE CASCADE: Delete the Child Records. (i.e. Cascade)

  2. ON DELETE SET NULL: Assign the NULL to the Foreign Key in the Child table (i.e SetNull).

  3. ON DELETE NO ACTION: Do nothing. The database will throw an error in case of Foreign Key violations. (Restrict/ NoAction)

  4. ON DELETE SET DEFAULT: Assign the Default Value. The database will throw an error if the default value breaks the Foreign Key rules.

The Entity Framework Core also defines the Referential actions. It refer them as Delete behaviors.

You can read more about relationships in entity framework core

Delete behaviors

The Entity Framework Core defines two sets of delete behaviors. Behaviors that maps to the database & those who do not. Those who do not map to the database starts with the prefix Client.

  1. Cascade: Delete the Child Records both in client & Database.
  2. ClientCascade: Delete the Child Records both in the client only.
  3. SetNull: Set Foreign Key as NULL in both in Client & Database.
  4. ClientSetNull: Set Foreign Key as NULL only in the Client
  5. NoAction: Default behavior on the client and No action on the database
  6. ClientNoAction: No action on the client and on the database
  7. Restrict: Same as NoAction. The migrations script will generate (Restrict or Non) instead of NoAction.

Setting the Delete behaviors

The EF Core defines the Delete behaviors in the DeleteBehavior enumerator. We can specify them while defining the relationships using the Fluent API.

For Example. The employee & the Department has one to many relationships. We setup delete behavior between them using the OnDelete method as shown below

The .OnDelete(DeleteBehavior.Cascade) assigns the delete Behavior to this relationship

Behaviors that maps to the database

The Cascade, SetNull, NoAction & Restrict are the actions that map to database referential action.

When you use the above behaviors to configure the relationship and use EF Core Migration to create the database, then the following cascade behavior will be set up for you.

ActionMapped to database
CascadeON DELETE CASCADE
NoActionON DELETE NO ACTION
SetNullON DELETE SET NULL
RestrictON DELETE RESTRICT (Not supported by SQL SERVER)

For Example, the following Fluent API DeleteBehavior.Cascade mapping

Results in the Employee table with CASCADE DELETE

If you are not using migrations then you will have to configure them manually in the database.

Behaviors that do not map to the database

If you are using ClientCascade, ClientSetNull, or ClientNoAction, then Migration will not generate the referential actions in the database.

That is the only difference between them.

Delete Behaviours in Tracked Entities

The Delete behavior only works on the entities that we load in the Memory (Tracked Entities). It will have no effect on the entities that we do not load.

For Database to delete the related entities we need to set up the Referential actions like FOR DELETE CASCADE or FOR DELETE SET NULL when we set up the ForeignKey.

For Example, consider the following query where we are deleting the department with id 3. It will have no effect on Employee Records as they are not loaded. When we call SaveChanges, DBContext will send the query to delete the department.

In the following query, we eagerly load the employee entity along with the Department using the Include method. The EF is now tracking both Department & Employee records.

When we delete the Department (db.Departments.Remove(dept)), depending on how we set up the DeleteBehavior, DbContext will do one of the following

  1. DeleteBehavior.Cascade/DeleteBehavior.ClientCascade
    Delete the Employee Entities

  2. DeleteBehavior.ClientSetNull/DeleteBehavior.SetNull:
    Updates the DepartmentID of Employee record to NULL

  3. DeleteBehavior.NoAction
    Updates the DepartmentID of Employee record to NULL

  4. DeleteBehavior.ClientNoAction:
    Does nothing.

  5. DeleteBehavior.Restrict:
    Updates the DepartmentID of Employee record to NULL

All of the above actions happen on the Client Side. When we call SaveChanges, DBContext will send the query to delete the department and also delete/update the tracked employee records

How untracked entity is treated depends in the delete behavior of the Database

Delete behaviors in Database

For Untracked entities, The database will do one of the following

  1. ON DELETE CASCADE: The Database will delete the Employee records.
  2. ON DELETE SET NULL: The DepartmentID the field is set to NULL in Employee Records.
  3. ON DELETE NO ACTION : The Database does nothing.
  4. ON DELETE SET DEFAULT: The DepartmentID is set to the default value.
  5. No Referential action: The Database does nothing. This is same as ON DELETE NO ACTION

Whether Tracked or untracked if any of the results of the operation violates the FOREIGN KEY constraint, then the database will raise an error.

Delete behaviors in Detail

Cascade / ClientCascade

The Context deletes the entities it tracks, when we delete the parent.

Cascade option creates a migration script with ON DELETE CASCADE, while ClientCascade creates a migration script with ON DELETE NO ACTION.

Cascade is the default behavior, when using the required relationship i.e Foreign key is Not Nullable

Untracked entities if any are deleted if the ON DELETE CASCADE is setup in the database. If not results in a FOREIGN KEY violation.

Not all databases support Cascade or does not support fully. Especially if there are cycles in relationships. Use ClientCascade and load all related entities before deleting the parent. The context will perform the Cascade Delete on the client-side.

SetNull / ClientSetNul

When we delete the parent, the Context sets values of foreign key properties in dependent entities to null on the entities it is tracking.

ClientSetNullis the default behavior, when using the optional relationship i.e Foreign key is nullable

SetNull option creates a migration script with ON DELETE SET NULL, while ClientSetNull creates a migration script with ON DELETE NO ACTION.

Untracked entities if any are also set to NULL if ON DELETE SET NULL is set up in the database. If not results in a FOREIGN KEY violation.

NoAction

When we delete the parent, the Context sets values of foreign key properties in dependent entities to null on the entities it is tracking.

Does not generate any migration script.

Database will throw an error in case of any FOREIGN KEY violation.

ClientNoAction

The Context does not modify or delete the entities it is tracking when we delete the parent

Does not generate any migration script.

Database will throw an error in case of any FOREIGN KEY violation.

Restrict

When we delete the parent, the Context sets values of foreign key properties of the dependent entities to null on the entities it is tracking.

Restrict option creates a migration script with ON DELETE NO ACTION

Database will throw an error in case of any FOREIGN KEY violation.

References

  1. DeleteBehaviour

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Scroll to Top