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();
 }