Entity Framework 6 Recipes 2nd Edition (12-5), recipes12-5
12-5. automatically delete associated entities
Problem
When an object is deleted, you want to automatically delete the object associated with it.
Solution
Suppose you have a table structure composed of a course (subject), course classes (course), and enrollment (register Student course Selection), as shown in Figure 12-5 :.
Figure 12-5.The Course, Class, and Enrollment tables in our database
Generate a model from the preceding table, as shown in Figure 12-6 :.
Figure 12-6.A model with the Course, Class, and Enrollment entities and their associations
When a course is deleted from the database, you want to delete all related classes, and the enrollments related to these classes are also deleted. to achieve this goal, we set a cascade deletion for this association in the Database Manager. In the Database Manager, select this association, select cascading deletion under "INSERT and UPDATE specifications" in the Properties window.
After these tables are imported to the model, the cascading deletion rule will also be imported. You can
Select the one-to-multiple relationship between Course and Class, and then see this cascading deletion rule in the attribute window, as shown in Figure 12-7.
Figure 12-7.The cascade delete rule from the database was imported into the model, and it is shown in the properties for the association
Cascade deletion rules, as shown in Figure 12-7, are at the concept layer. there is also a type rule in the storage layer. when an object is deleted, EF rules and cascade deletion rules in the database are required to synchronize the object context and database.
The Listing 12-5 Code demonstrates cascading deletion.
Listing 12-5.Using the Underlying Cascade Delete Rules to Delete the Related Objects
Class Program
{
Static void Main (string [] args)
{
RunExample ();
}
Static void RunExample ()
{
Using (var context = new EFRecipesEntities ())
{
Var course1 = new Course {CourseName = "CS 301 "};
Var course2 = new Course {CourseName = "Math 455 "};
Var en1 = new Enrollment {Student = "James Folk "};
Var en2 = new Enrollment {Student = "Scott Shores "};
Var en3 = new Enrollment {Student = "Jill Glass "};
Var en4 = new Enrollment {Student = "Robin Rosen "};
Var class1 = new Class {extends uctor = "Bill Meyers "};
Var class2 = new Class {Instructor = "Norma Hall "};
Class1.Course = course1;
Class2.Course = course2;
Class1.Enrollments. Add (en1 );
Class1.Enrollments. Add (en2 );
Class2.Enrollments. Add (en3 );
Class2.Enrollments. Add (en4 );
Context. Classes. Add (class1 );
Context. Classes. Add (class2 );
Context. SaveChanges ();
Context. Classes. Remove (class1 );
Context. SaveChanges ();
}
Using (var context = new EFRecipesEntities ())
{
Foreach (var course in context. Courses)
{
Console. WriteLine ("Course: {0}", course. CourseName );
Foreach (var c in course. Classes)
{
Console. WriteLine ("\ tClass: {0}, Instructor: {1 }",
C. ClassId. ToString (), c. extends uctor );
Foreach (var en in c. Enrollments)
{
Console. WriteLine ("\ t \ tStudent: {0}", en. Student );
}
}
}
}
Console. WriteLine ("Press any key to close ...");
Console. ReadLine ();
}
}
The output result of the Listing 12-5 code is as follows:
Course: CS 301
Course: Math 455
Class: 8, Instructor: Norma Hall
Student: Jill Glass
Student: Robin Rosen
Principle
In this section, the database and model define cascading deletion rules. In the model, the object context is synchronized with the database. This rule appears at both the concept layer and the storage layer.
Best practices
Now you may ask: "Why do we need to define this rule in both the database and the model? Can't it be defined only in models or databases ?", Cascading deletion exists in the concept layer to ensure that the objects loaded by the object context are synchronized with the results of cascading deletion of the database. for example, if we have loaded the relevant course and course selection information for a subject in object context, then we mark this subject as deleted, EF marks the course and course selection information of the subject as deleted. before submitting a deletion request to a database, in the model layer, cascade deletion means that the associated object is deleted only when the associated object mark is deleted. In the end, EF deletes the object. so since EF deletes objects, why can't it only define cascading deletion in the model? The reason is: in order for EF to delete the entity mark, DbContext must first load these entities. Imagine that if our subject has been loaded, but the relevant course is not loaded with the student course selection information, if we delete a subject, the related course and Student Course Selection information cannot be deleted because it is not loaded by DbContext, in this case, commands for deleting related records cannot be sent to the database. however, if we define cascade deletion in the database, the database will perform cascade deletion well.
The best practice here is to define cascading deletion rules in both the model and database.
If you add a cascading deletion rule to a model, EF will not overwrite this rule, even if you update the model from the database.
Unfortunately, if you have not added a cascade deletion rule to the model, and then you update the entity from the database, EF will not add a new cascade deletion rule to the concept layer in the database, you will have to manually add it.
Appendix: script file of the database used in the Creation example