引言
在主表中指定Key,子表中指定Required后,並不會在數據庫中生成級聯刪除的外鍵。那怎么才能使EF在數據中生成級聯刪除的外鍵?
SQLServer數據庫中級聯刪除功能配置界面:
上圖中顯示只用[required]特性后生成的外鍵沒有級聯刪除動作。
看似正確的解決方案。(治標的處理方式)
版本:EF6.0.1 RC
一對多場景,在子對象映射中開啟級聯刪除情況下,刪除父對象將自動刪除其下所有子對象,需要注意一些事項:
√ 需要保證DbContext中已經加載了該父對象的所有子對象。
X
如果DbContext內未加載子對象將不級聯刪除子對象,X
如DbContext只加載部分子對象也只級聯刪除這些子對象。因此在查詢父對象只應該使用Include("子對象屬性名")查詢(請看示例代碼3)或者在DbContext另外把其下所有子對象查詢出來(請看示例代碼4),再進行對父對象的刪除方可級聯刪除子對象。
但注意以上所述情況只適用於關聯子項比較少的情況,數據量少的演示測試Demo可以,工作中應該杜絕該類解決方案的出現。
真正的解決方案(治本的處理方式)
以下摘自是EntityFrameWork 官網原文
----------------------------------------------------------------
You can configure cascade delete on a relationship by using the WillCascadeOnDelete method. If a foreign key on the dependent entity is not nullable, then Code First sets cascade delete on the relationship. If a foreign key on the dependent entity is nullable, Code First does not set cascade delete on the relationship, and when the principal is deleted the foreign key will be set to null.
You can remove these cascade delete conventions by using:
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>()
modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>()
The following code configures the relationship to be required and then disables cascade delete.
modelBuilder.Entity<Course>()
.HasRequired(t => t.Department)
.WithMany(t => t.Courses)
.HasForeignKey(d => d.DepartmentID)
.WillCascadeOnDelete(false);
EF到底怎么搞定級聯刪除
Setting Cascade on a relation in EF designer instructs EF to execute DELETE
statement for each loaded realated entity. It doesn't say anything about ON CASCADE DELETE
in the database.
Setting Cascade deletion when using EF needs two steps:
- Set Cascade on relation in EF designer. This instruct context that all loaded related entitiesmust be deleted prior to deletion of the parent entity. If this doesn't happen EF will throw exception because internal state will detect that loaded childs are not related to any existing parent entity even the relation is required. I'm not sure if this happens before execution of delete statement of the parent entity or after but there is no difference. EF doesn't reload related entities after executing modifications so it simply doesn't know about cascade deletes triggered in the database.
- Set
ON CASCADE DELETE
on relation in database. This will instruct SQL to delete all related records which were not loaded to context in the time of deleting the parent.
The implementation of cascade deletes in EF is strange and quite inefficient but this is how it behaves and if you want to use it, you must modify your application to behaves correctly in this scenario.
總結
- 問題解決的時候我們應該從事由表及里,不能只停留在問題表面,而應該找出問題真實的原因。
- 在使用現有框架時,我們有必要把其基礎原理搞清楚,也有必要把其使用場景搞清楚。(就像物理中許多定理中都有一個假設條件,而這個假設條件是這個定理成立的充分條件)
參考
EF里的默認映射以及如何使用Data Annotations和Fluent API配置數據庫的映射
Entity Framework 4.3 delete cascade with code first (Poco)
Cascading Deletes in LINQ to SQL
Cascading deletes with Entity Framework - Related entities deleted by EF