12-5. 自動刪除相關聯實體問題當一個實體被刪除時,你想自動刪除它相關聯的實體解決方案假設你有一個表結構由一個course (科目), course 的classes (課程),以及enrollment (登記學生選課),如 Figure 12-5所示:.Figure 12-5. The Cour...
12-5. 自動刪除相關聯實體
問題
當一個實體被刪除時,你想自動刪除它相關聯的實體
解決方案
假設你有一個表結構由一個course (科目), course 的classes (課程),以及enrollment (登記學生選課),如 Figure 12-5所示:.
Figure 12-5. The Course, Class, and Enrollment tables in our database
由上述表生成一個模型,如下圖Figure 12-6所示:.
Figure 12-6. A model with the Course, Class, and Enrollment entities and their associations
當一個course從資料庫里被刪除,你想把所有的相關classes也被刪除,而且與這些classes相關的enrollments也被刪除.為了實現這個目標,我們在資料庫管理器中為這個關聯設置一個級聯刪除,在資料庫管理器中,選擇該關聯,在屬性視窗的”INSERT 和UPDATE規範”下麵選擇級聯刪除.
當這些表導入到模型後,這個級聯刪除規則也會被導入,你可以
選擇Course 和Class之間的一對多關係中然後在屬性視窗里看到這個級聯刪除規則,如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
如Figure 12-7所示的級聯刪除規則是在概念層的.在存儲層也有一個類型的規則. 當一個對象被刪除,EF規則及資料庫里的級聯刪除規則,這二者是有必要使object context 和資料庫保持同步.
Listing 12-5 代碼演示了級聯刪除
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 { Instructor = "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.Instructor);
foreach (var en in c.Enrollments)
{
Console.WriteLine("\t\tStudent: {0}", en.Student);
}
}
}
}
Console.WriteLine("Press any key to close...");
Console.ReadLine();
}
}
上述Listing 12-5代碼輸出結果如下:
Course: CS 301
Course: Math 455
Class: 8, Instructor: Norma Hall
Student: Jill Glass
Student: Robin Rosen
原理
本小節里資料庫與模型都定義了級聯刪除規則.在模型里,以確保object context與資料庫同步.這個規則同時出現在概念層與存儲層.
最佳實踐
那麼現在你可能會問:”為什麼我們需要在資料庫里與模型都定義這條規則?不能只在模型或是資料庫里定義嗎?”,級聯刪除存在於概念層來保持object context載入的對象是與資料庫的級聯刪除後的結果是同步的.例如,如果我們已經在object context里為一個科目載入了相關的課程以及學生選課信息,然後我們把這個科目標誌為刪除,EF同樣會把該科目的課程以及學生選課信息標誌為刪除.在把刪除提交到資料庫以前,在模型層,級聯刪除意味著只是把相關聯的實體標誌為刪除,最終,EF才會把實體刪除.那麼既然EF會刪除實體,那麼為什麼不能只在模型中定義級聯刪除呢?原因是: EF為了給實體標誌為刪除, DbContext 必須先載入這些實體,想象一下,如果我們的科目已被載入,但是相關的課程以學生選課信息未被載入,我們刪除了科目,那麼相關的課程及學生選課信息,由於未被DbContext 載入,所以EF無法將相關的實體標誌為刪除,也就無法向資料庫發送刪除相關記錄的命令. 然而,如果我們在資料庫里定義了級聯刪除,那麼資料庫自己就會很好的完成級聯刪除工作.
這裡的最佳實踐就是:在模型與資料庫里同時定義級聯刪除規則.
如果你在一個模型里添加了一個級聯刪除規則,那麼EF不會覆蓋這條規則,即使你從資料庫更新模型.
不幸的是,如果你沒有在模型里添加級聯刪除規則,然後你從資料庫更新實體,EF也不會向概念層添加在資料庫里新添加的級聯刪除規則,你將不得不手動添加它.