Cascade Delete in Entity Framework Code First Approach

Cascade Delete in Entity Framework Code First Approach

In this article, I am going to discuss How to Perform Cascade Delete in Entity Framework Code First Approach with Examples. Please read our previous article where we discussed How to Perform CUD Operations using Stored Procedures in Entity Framework Code-First Approach.

Cascade Delete in Entity Framework Code First Approach

Cascade Delete automatically deletes dependent records (child records) or sets null to Foreign Key columns when the parent record is deleted in the database. The point that you need to remember is by default, cascade delete is enabled in Entity Framework for all types of relationships such as one-to-one, one-to-many and many-to-many.

Cascade Delete in One-to-One Relationships

Let us understand How Cascade Delete work in One-to-One Relationships. For this to understand, we need to create two entities with one-to-one relationships. Please have a look at the following Student and StudentAddress entities which have a one-to-one or one-to-zero relationship as per our requirement.

Create a class file with the name Student.cs and then copy and paste the following code into it.

namespace EFCodeFirstDemo
{
    public class Student
    {
        public int StudentId { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public virtual StudentAddress Address { get; set; }
    }
}

Create a class file with the name StudentAddress.cs and then copy and paste the following code into it. In the below example, we are making the StudentAddressId property both Primary Key as well as foreign Key which will make the relationship between the Student and StudentAddress entities one-to-one or one-to-zero.

using System.ComponentModel.DataAnnotations.Schema;
namespace EFCodeFirstDemo
{
    public class StudentAddress
    {
        [ForeignKey("Student")]
        public int StudentAddressId { get; set; }
        public string AddressLine1 { get; set; }
        public string AddressLine2 { get; set; }
        public int PinCode { get; set; }
        public string City { get; set; }
        public string State { get; set; }
        public string Country { get; set; }
        public virtual Student Student { get; set; }
    }
}

So, we have configured a one-to-zero or one-to-one relationship between Student and StudentAddress entities where the Student entity can be saved without attaching the StudentAddress object to it but the StudentAddress entity cannot be saved without attaching an object of the Student entity. This makes one end required.

Please make sure to have the connection string with the name MyConnectionString within the app.config file or web.config file as shown in the below image.

How to Perform Cascade Delete in Entity Framework Code First Approach with Examples

Next, modify the context class as follows.

using System.Data.Entity;
namespace EFCodeFirstDemo
{
    public class EFCodeFirstContext : DbContext
    {
        public EFCodeFirstContext() : base("name=MyConnectionString")
        {
            //Setting the Database Initializer as DropCreateDatabaseAlways
            Database.SetInitializer(new DropCreateDatabaseAlways<EFCodeFirstContext>());
        }

        public DbSet<Student> Students { get; set; }
        public DbSet<StudentAddress> StudentAddresses { get; set; }
    }
}

To Understand the cascade delete operation, please modify the Main method of the Program class as follows. Here, first, we are creating one student and student address entities. Then attaching the Student Address entity with the address property of the Student Entity. Then we are calling the SaveChanges method and when we call the SaveChanges method, both Student and StudentAddress entities are going to be saved in the database. Then we are removing the student entity and when we remove the student entity and when we call the SaveChanges method, then not only the student entity but also the corresponding student address will be removed from the database.

using System;
namespace EFCodeFirstDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            using (EFCodeFirstContext context = new EFCodeFirstContext())
            {
                var student = new Student() { FirstName = "Pranaya", LastName = "Rout" };
                var address = new StudentAddress() { AddressLine1 = "address1", City = "BBSR", Country = "India" };

                student.Address = address;
                context.Students.Add(student);
                //When we call the SaveChanges Method, both Student and 
                //StudentAddress are going to be saved in the DB
                context.SaveChanges();

                //When we remove the student, its corresponding address will be removed from db 
                //when we call the SaveChanges method
                context.Students.Remove(student);
                context.SaveChanges();
            }
            Console.ReadKey();
        }
    }
}

Now, run the application and verify the database and you will see that both the student and student addresses should be deleted from the database. This is how Cascade Delete works with One-to-One or One-to-Zero relationships.

Cascade Delete in One-to-Many Relationships

Let us understand How Cascade Delete work in One-to-Many Relationships with one example. For this to understand, we need to create two entities with one-to-many relationships. Please have a look at the following Student and Standard entities which have a one-to-many relationship as per our requirement.

Student.cs:
namespace EFCodeFirstDemo
{
    public class Student
    {
        public int StudentId { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public virtual Standard Standard { get; set; }
    }
}
Standard.cs:
using System.Collections.Generic;
namespace EFCodeFirstDemo
{
    public class Standard
    {
        public int StandardId { get; set; }
        public string StandardName { get; set; }
        public string Description { get; set; }
        public ICollection<Student> Students { get; set; }
    }
}

As you can see in the above two classes, the Student entity includes a reference navigation property of the Standard type and the Standard entity includes a collection navigation property of the ICollection<Student> type which results in a one-to-many relationship between Students and Standards tables in the database. Next, modify the Context class as follows.

using System.Data.Entity;
namespace EFCodeFirstDemo
{
    public class EFCodeFirstContext : DbContext
    {
        public EFCodeFirstContext() : base("name=MyConnectionString")
        {
            //Setting the Database Initializer as DropCreateDatabaseAlways
            Database.SetInitializer(new DropCreateDatabaseAlways<EFCodeFirstContext>());
        }

        public DbSet<Student> Students { get; set; }
        public DbSet<Standard> Standards { get; set; }
    }
}

To Understand the Cascade Delete operation, please modify the Main method of the Program class as follows. Here, first, we are creating two student entities and one standard entity. Then attaching the standard entity with the standard property of the Student Entity. Then we are calling the SaveChanges method and when we call the SaveChanges method, both Students and Standard entities are going to be saved in the database. Then we are removing the standard entity and when we remove the standard entity and when we call the SaveChanges method, then it will remove the standard entity from the database, and also set the foreign key column value to null in the Student table.

using System;
namespace EFCodeFirstDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            using (EFCodeFirstContext context = new EFCodeFirstContext())
            {
                var student1 = new Student() { FirstName = "Pranaya", LastName = "Rout" };
                var student2 = new Student() { FirstName = "Anurag", LastName = "Mohanty" };

                var standard1 = new Standard() { StandardName = "Standard 1", Description = "Standard One" };

                student1.Standard = standard1;
                student2.Standard = standard1;

                context.Students.Add(student1);
                context.Students.Add(student2);
                Console.WriteLine("Students and Standard Added");
                //Inserts students and standard1 into database
                context.SaveChanges();

                // deletes standard1 from database and also set standard_StandardId FK column in Students table to null for
                // all the students that reference standard1.
                context.Standards.Remove(standard1);
                context.SaveChanges();
                Console.WriteLine("Standard Deleted");
            }
            Console.ReadKey();
        }
    }
}

Now, run the application and verify the database and you will see the following.

How to Perform Cascade Delete in Entity Framework Code First Approach with Examples

Cascade Delete in Many-to-Many Relationships

Let us understand How Cascade Delete work in Many-to-Many Relationships with one example. For this to understand, we need to create two entities with many-to-many relationships. Please have a look at the following Student and Course entities which have a many-to-many relationship as per our requirement. Implementing the Many-to-Many relationship is very simple, we just need to include a collection navigation property at both ends i.e. at both entities.

Student.cs
using System.Collections.Generic;
namespace EFCodeFirstDemo
{
    public class Student
    {
        public Student()
        {
            this.Courses = new HashSet<Course>();
        }
        public int StudentId { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }

        public virtual ICollection<Course> Courses { get; set; }
    }
}
Course.cs
using System.Collections.Generic;
namespace EFCodeFirstDemo
{
    public class Course
    {
        public Course()
        {
            this.Students = new HashSet<Student>();
        }

        public int CourseId { get; set; }
        public string CourseName { get; set; }

        public virtual ICollection<Student> Students { get; set; }
    }
}

As you can see in the above example, the Student entity has a collection navigation property of Course type, and the Course entity also has a collection navigation property of Student type which create a many-to-many relationship between them. Next, modify the context class as follows.

using System.Data.Entity;
namespace EFCodeFirstDemo
{
    public class EFCodeFirstContext : DbContext
    {
        public EFCodeFirstContext() : base("name=MyConnectionString")
        {
            //Setting the Database Initializer as DropCreateDatabaseAlways
            Database.SetInitializer(new DropCreateDatabaseAlways<EFCodeFirstContext>());
        }

        public DbSet<Student> Students { get; set; }
        public DbSet<Course> Courses { get; set; }
    }
}

Next, modify the Main Method of the Program class as follows. The point that you need to remember is Entity Framework will automatically delete the related records from the joining table for many-to-many relationships if one or the other entity is deleted.

using System;
using System.Collections.Generic;
namespace EFCodeFirstDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            using (EFCodeFirstContext context = new EFCodeFirstContext())
            {
                var courses = new List<Course>
                {
                    new Course() { CourseName = "C#"},
                    new Course() { CourseName = "ASP.NET Core" }
                };
                
                var student = new Student() { FirstName = "Pranaya", LastName = "Rout", Courses = courses };
                context.Students.Add(student);
                context.SaveChanges();
                Console.WriteLine("Student and Courses Added");

                context.Students.Remove(student);
                context.SaveChanges();
                Console.WriteLine("Student Removed");
            }
            Console.ReadKey();
        }
    }
}

With the above changes in place, run the application and verify the database. The Entity Framework will create Students, Courses, and the joining table StudentCourses in the database.

Note: Entity Framework, by default, enables the cascading deletion for all the entities and for all types of relationships.

How to turn off Cascade Delete using Entity Framework?

We can use Entity Framework Fluent API to turn off Cascade Delete using the WillCascadeOnDelete() method. For a better understanding, please modify the context class as follows.

using System.Data.Entity;
namespace EFCodeFirstDemo
{
    public class EFCodeFirstContext : DbContext
    {
        public EFCodeFirstContext() : base("name=MyConnectionString")
        {
            //Setting the Database Initializer as DropCreateDatabaseAlways
            Database.SetInitializer(new DropCreateDatabaseAlways<EFCodeFirstContext>());
        }
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Student>()
                .HasOptional(s => s.Standard)
                .WithMany()
                .WillCascadeOnDelete(false);
        }
        public DbSet<Student> Students { get; set; }
        public DbSet<Standard> Standards { get; set; }
    }
}

Note: No Data Annotation Attribute is available to turn off cascade delete in Entity Framework.

In the next article, I am going to discuss How to Seed Data into Database Tables using Entity Framework Code-First Approach with Examples. Here, in this article, I try to explain Cascade Delete in Entity Framework Code First Approach with Examples. I hope you enjoyed this Cascade Delete in Entity Framework Code First Approach article. Please give your valuable feedback and suggestions about this article.

Leave a Reply

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