简体   繁体   English

实体框架级联删除 - FOREIGN KEY约束

[英]Entity Framework Cascade delete - FOREIGN KEY constraint

I have a problem with the following model: 我有以下型号的问题:

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

On model Creating I have this: 在模型创建我有这个:

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

But I can't update database. 但我无法更新数据库。 I've got the following error in the Package Manager console: 我在Package Manager控制台中遇到以下错误:

Introducing FOREIGN KEY constraint 'FK_dbo.ProjectPages_dbo.ProjectPages_FooterId' on table 'ProjectPages' may cause cycles or multiple cascade paths. 在表'ProjectPages'上引入FOREIGN KEY约束'FK_dbo.ProjectPages_dbo.ProjectPages_FooterId'可能会导致循环或多个级联路径。 Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints. 指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他FOREIGN KEY约束。

Can somebody explain how to remove the Project Page (which can be Footer or Header in another Project Page)? 有人可以解释如何删除项目页面(可以是另一个项目页面中的页脚或页眉)?

That exception is caused when you have multiple paths of cascade deletes that could end trying to delete the same row in DB. 如果有多个级联删除路径可能会导致尝试删除DB中的同一行,则会导致该异常。 Imagine if you have ProjectPage with the same Header and Footer . 想象一下,如果你的ProjectPage具有相同的HeaderFooter When you try to delete that ProjectPage , due to the configuration of your relationships, there will be two paths trying to delete the same row in DB (one for the Header and another for the Footer ). 当您尝试删除该ProjectPage ,由于您的关系配置,将有两个路径尝试删除DB中的同一行(一个用于Header ,另一个用于Footer )。

You can avoid such ambiguous delete paths by either disabling cascading delete in one of two relationship using Fluent API or by defining some of the relationships as optional (with a nullable foreign key, but you can not configure the relationship with cascade delete). 您可以通过使用Fluent API禁用两个关系之一中的级联删除,或者将某些关系定义为可选(使用可为空的外键,但无法使用级联删除配置关系)来避免此类不明确的删除路径。

Update 更新

Is true, you have both FK as optionals but both relationships have been configured with cascade delete, that's why EF is throwing that exception. 是的,你有两个FK作为选项,但两个关系都配置了级联删除,这就是EF抛出异常的原因。 My recommendation is set only one relationship with cascade delete. 我的建议只与级联删除设置了一个关系。 Regarding the other relationship, I'm afraid you you have to do it manually. 关于其他关系,我担心你必须手动完成。 If you, for example, choose Footer to be deleted manually, then when you are going to remove a ProjectPage ,you have to set the Footer property as null . 例如,如果您选择手动删除Footer ,那么当您要删除ProjectPage ,您必须将Footer属性设置为null The problem here is you could have orphans in your DB. 这里的问题是你的DB中可能有孤儿。 To avoid that, you can override the SaveChanges on your Context to find and delete orphans: 为避免这种情况,您可以覆盖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();
}

Another way could be setting the FooterId with the default(Guid) value. 另一种方法是使用default(Guid)值设置FooterId Due to the type of your PK property ( Id ) is Guid and it is not Identity, you have to set that property before add a ProjectPage to the DB. 由于您的PK属性( Id )的类型是Guid而且它不是Identity,您必须在将ProjectPage添加到DB之前设置该属性。 So, setting the FooterId with default(Guid) is another way to mark that entity that you want to delete. 因此,将FooterId设置为default(Guid)是另一种标记要删除的实体的方法。 If you choose this variant, your SaveChanges method could be as I show below: 如果您选择此变体,您的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();
 }

Or: 要么:

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

This way you can avoid call the Find method. 这样就可以避免调用Find方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 实体框架核心,由于级联删除导致的外键约束 - Entity Framework core, foreign key constraint due to cascade delete 如何在实体框架中对外键应用级联删除 - how to apply cascade-delete on foreign key in entity framework 实体框架外键约束 - Entity framework foreign key constraint SQL 错误:引入 FOREIGN KEY 约束可能会导致循环或多个级联路径。 实体框架核心 - SQL Error: Introducing FOREIGN KEY constraint may cause cycles or multiple cascade paths. Entity Framework Core 实体框架,外键约束可能会导致循环或多个级联路径 - Entity Framework, Foreign key constraint may cause cycles or multiple cascade paths 实体框架:在表 '' 上引入 FOREIGN KEY 约束 '' 可能会导致循环或多个级联路径 - Entity Framework: Introducing FOREIGN KEY constraint '' on table '' may cause cycles or multiple cascade paths 引入 FOREIGN KEY 约束...可能导致循环或多个级联路径 - 实体框架 - Introducing FOREIGN KEY constraint ... may cause cycles or multiple cascade paths - Entity Framework 如何使用可选外键将实体框架设置为删除级联? - How do you set Entity Framework to cascade on delete with optional foreign key? 即使级联删除已关闭,也会获得“外键约束” - Getting “Foreign Key constraint” even though cascade delete is turned off 实体框架 - 代码优先 - 外键约束 - Entity Framework - Code First - Foreign Key Constraint
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM