C# 实体框架级联删除-外键约束
我对以下模型有问题:C# 实体框架级联删除-外键约束,c#,entity-framework,entity-framework-6,C#,Entity Framework,Entity Framework 6,我对以下模型有问题: 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; }
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);
modelBuilder.Entity().HasOptional(p=>p.Header).WithMany().HasForeignKey(p=>p.HeaderId).WillCascadeOnDelete(true);
modelBuilder.Entity().HasOptional(p=>p.Footer).WithMany().HasForeignKey(p=>p.FooterId).WillCascadeOnDelete(true);
但我不能更新数据库。包管理器控制台中出现以下错误:
引入外键约束
表上的“FK_dbo.ProjectPages_dbo.ProjectPages_FooterId”
“ProjectPages”可能导致循环或多个级联路径。指明
删除无操作或更新无操作,或修改其他外键
限制
有人能解释一下如何删除项目页面(可以是另一个项目页面中的页脚或页眉)?当您有多个级联删除路径时,会导致异常,这些路径可能会导致您尝试删除数据库中的同一行。想象一下,如果您的
ProjectPage
具有相同的页眉
和页脚
。当您尝试删除该ProjectPage
时,由于关系的配置,将有两个路径尝试删除数据库中的同一行(一个用于页眉
,另一个用于页脚
)
通过使用禁用两个关系中的一个关系中的级联删除,或者将某些关系定义为可选关系(使用可为空的外键,但不能使用级联删除配置关系),可以避免这种不明确的删除路径
更新
如果为true,则两个FK都是可选的,但两个关系都配置了级联删除,这就是EF引发该异常的原因。我的建议是只设置一个与级联删除的关系。关于另一种关系,恐怕你必须手动进行。例如,如果选择要手动删除的Footer
,则当您要删除ProjectPage
时,必须将Footer
属性设置为null
。这里的问题是,数据库中可能有孤儿。为了避免这种情况,您可以覆盖上下文中的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)
值设置footer id
。由于PK属性(Id
)的类型是Guid
,并且不是Identity,因此在将ProjectPage
添加到DB之前,必须设置该属性。因此,使用default(Guid)
设置FooterId
,是标记要删除的实体的另一种方法。如果您选择此变量,您的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();
}
或:
这样可以避免调用
Find
方法。但是当我删除级联删除时,它会显示行具有依赖性,并且无法删除它。。。我有可选的外键。所以,在我从表中删除页脚或页眉之前,我需要自己在所有依赖项中创建空页眉或页脚?您好@AndreyMykhaylov,我已经更新了我的答案,希望现在对您有所帮助。
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();
}