EF 默認是開戶級聯刪除的,這此規則將會刪除非空外鍵和多對多的關系,如果 在數據庫上下文中的實體模型類 存在着 級聯引用和多重刪除路徑,那么EF就拋出 級聯引用和多重刪除路徑的異常。
Introducing FOREIGN KEY constraint 'FK_dbo.ReviewIndexSystem_dbo.Category_CategoryID' on table
'ReviewIndexSystem' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO
ACTION, or modify other FOREIGN KEY constraints.
Could not create constraint. See previous errors.
如果一個實體類的一個屬性類的名稱為ID(Id\id) 或為ClassNameID ,EF約定它就默認為是該類的主鍵。
如果一個實體類的一個屬性名為 導航屬性名+它的主鍵名,或簡單的為 導航屬性的類名的主鍵名,那么約定它為兩實體間的外鍵。
如果主鍵、外鍵屬性名字不滿足以上規則,就可以通過 [Key]、[Foreingkey]來指定關系。
對一一對一或者一對多關系,要在依賴的實體上加上[ForeignKey]屬性指明依賴,因為EF不知道哪是主要的哪是依賴的。
可能通過設置 外鍵值為空(string 類型外鍵默認為空。int等值類型的默認不為空,可以加?使之為空,比如int? PersonID 的外鍵)或者使用Fluent API來 關閉默認的級聯刪除規則。
1、可以在數據庫上下文類的 覆寫OnModelCreating()方法來 關閉整個全局的級聯刪除規則:
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>(); //關閉一對多的級聯刪除。
modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>(); //關閉多對多的級聯刪除。
2、可以在此方法中關閉個別實體間的級聯刪除規則:
//導航屬性,用於FluentAPI來設置 刪除EF 默認的級聯刪除規則。如果不配置級聯刪除,此模型將會導致循環或者多個刪除路徑。
modelBuilder.Entity<ReviewIndexItem>().HasRequired(indexItem => indexItem.Category).WithMany(cate => cate.ReviewIndexItems).WillCascadeOnDelete(false);
modelBuilder.Entity<ReviewIndexSystem>().HasRequired(indexSystem => indexSystem.Category).WithMany(cate => cate.ReviewIndexSystems).WillCascadeOnDelete(false);
modelBuilder.Entity<ReviewProject>().HasRequired(reviewProject => reviewProject.Category).WithMany(cate => cate.ReviewProjects).WillCascadeOnDelete(false);
在Code First 開發方式中,常作用數據注解和Fluent API 來配置實體間的關系。
1、如果使用[Requied]數據注解配置一個實體類的外鍵,則表明此類 僅指明了映射關系中對方不能為空,也包含了客戶端的驗證,和服務器端的驗證。
public class A
{
[Required]
[Display(Name="評審項目類別")]
public string CategoryID { get; set; }
[Display(Name = "評審項目類別")]
public virtual Category Category { get; set; }
}
2、如果使用Fluent API來配置,則只添加實體間的關系,而不添加實體間的驗證規則。
判斷關系一方是否為0,取決於外鍵屬性的類型,string 類型的外鍵默認可空,也就是說 是0或1 對*的關系,或者 01對1。
//假設我們關閉Requied 驗證屬性,使用FluentAPI來配置 1對多的關系。
modelBuilder.Entity<ReviewIndexUseItem>().HasRequired(useItem => useItem.ReviewIndexItem).WithMany(item => item.ReviewIndexUseItems);
modelBuilder.Entity<ReviewIndexUseItem>().HasRequired(useItem => useItem.ReviewIndexSystem).WithMany(system => system.ReviewIndexUseItems);
3、EF在調用SaveChanges()方法的時候 ,會報錯誤。
當EF調用 context.SaveChanges()方法的時候 ,會默認檢查 所有改變實體的所有屬性,一旦發現實體任何一個屬性不能滿足的驗證規則,會拋出"一個或多個實體的驗證失敗請參閱“EntityValidationErrors”屬性。"的異常。
第一種方式可以通過Fluent API來配置關系,而不添加驗證規則,避免錯誤發生。
第二種方式是可以通過 在調用SaveChange()方法前臨時關閉掉實體驗證,驗證,dbContext.Configuration.ValidateOnSaveEnabled = false; 關閉Savechanges的驗證。)
所以使用[Required] 數據注解除了指定了實體間非空的關系,還帶來了驗證規則。容易引發saveChanges()時的驗證錯誤。
使用[Requied] 來定義外鍵關系非空不是好方法,FlentAPI才是好辦法。因為[Required]既指定了非空的外鍵關系,又添加了
模型非空的驗證的規則。而后者只指定了實體間的關系。
