[英]Entity Framework Cascade delete - FOREIGN KEY constraint
我有以下型號的問題:
public class ProjectPage
{
[Key]
public Guid Id { get; set; }
public Guid? HeaderId { get; set; }
public ProjectPage Header { get; set; }
public Guid? FooterId { get; set; }
public ProjectPage Footer { get; set; }
}
在模型創建我有這個:
modelBuilder.Entity<ProjectPage>().HasOptional(p => p.Header).WithMany().HasForeignKey(p => p.HeaderId).WillCascadeOnDelete(true);
modelBuilder.Entity<ProjectPage>().HasOptional(p => p.Footer).WithMany().HasForeignKey(p => p.FooterId).WillCascadeOnDelete(true);
但我無法更新數據庫。 我在Package Manager控制台中遇到以下錯誤:
在表'ProjectPages'上引入FOREIGN KEY約束'FK_dbo.ProjectPages_dbo.ProjectPages_FooterId'可能會導致循環或多個級聯路徑。 指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他FOREIGN KEY約束。
有人可以解釋如何刪除項目頁面(可以是另一個項目頁面中的頁腳或頁眉)?
如果有多個級聯刪除路徑可能會導致嘗試刪除DB中的同一行,則會導致該異常。 想象一下,如果你的ProjectPage
具有相同的Header
和Footer
。 當您嘗試刪除該ProjectPage
,由於您的關系配置,將有兩個路徑嘗試刪除DB中的同一行(一個用於Header
,另一個用於Footer
)。
您可以通過使用Fluent API禁用兩個關系之一中的級聯刪除,或者將某些關系定義為可選(使用可為空的外鍵,但無法使用級聯刪除配置關系)來避免此類不明確的刪除路徑。
是的,你有兩個FK作為選項,但兩個關系都配置了級聯刪除,這就是EF拋出異常的原因。 我的建議只與級聯刪除設置了一個關系。 關於其他關系,我擔心你必須手動完成。 例如,如果您選擇手動刪除Footer
,那么當您要刪除ProjectPage
,您必須將Footer
屬性設置為null
。 這里的問題是你的DB中可能有孤兒。 為避免這種情況,您可以覆蓋Context上的SaveChanges
來查找和刪除孤兒:
public override int SaveChanges()
{
ProjectPages
.Local
.Where(r => r.Footer== null && r.FooterId!=default(Guid)).Select(r=>r.FooterId)
.ToList()
.ForEach(id => ProjectPages.Remove(ProjectPages.Find(id)));
return base.SaveChanges();
}
另一種方法是使用default(Guid)
值設置FooterId
。 由於您的PK屬性( Id
)的類型是Guid
而且它不是Identity,您必須在將ProjectPage
添加到DB之前設置該屬性。 因此,將FooterId
設置為default(Guid)
是另一種標記要刪除的實體的方法。 如果您選擇此變體,您的SaveChanges
方法可能如下所示:
public override int SaveChanges()
{
ProjectPages
.Local
.Where(r => r.Footer!= null && r.FooterId!=default(Guid)).Select(r=>r.Footer)
.ToList()
.ForEach(pp=> ProjectPages.Remove(pp));
return base.SaveChanges();
}
要么:
public override int SaveChanges()
{
ProjectPages
.Local
.Where(r => r.Footer!= null && r.FooterId!=default(Guid)).Select(r=>r.Footer)
.ToList()
.ForEach(pp=> Entry(pp).State=EntityState.Deleted);
return base.SaveChanges();
}
這樣就可以避免調用Find
方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.