实体框架级联删除 - FOREIGN KEY约束 [英] Entity Framework Cascade delete - FOREIGN KEY constraint

查看:76
本文介绍了实体框架级联删除 - FOREIGN KEY约束的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下模型的问题:

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:


介绍FOREIGN KEY约束
'FK_dbo.ProjectPages_dbo.ProjectPages_FooterId'在表
'ProjectPages'可能会导致循环或多个级联路径。指定ON
删除无操作或更新无操作,或修改其他FOREIGN KEY
约束。

Introducing FOREIGN KEY constraint 'FK_dbo.ProjectPages_dbo.ProjectPages_FooterId' on table 'ProjectPages' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.

可以有人解释了如何删除项目页面(可以在另一个项目页面中的页脚或页眉)?

Can somebody explain how to remove the Project Page (which can be Footer or Header in another Project Page)?

推荐答案

引发异常当您有多个级联删除路径时,可能会尝试删除DB中的同一行。想象一下,如果您有 ProjectPage 与相同的标头页脚 。当您尝试删除 ProjectPage 时,由于您的关系配置,将有两个路径尝试删除DB中的同一行(一个用于标题,另一个 Footer )。

That exception is caused when you have multiple paths of cascade deletes that could end trying to delete the same row in DB. Imagine if you have ProjectPage with the same Header and Footer. 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).

你可以避免这种模糊通过使用 Fluent API 在两种关系之一中禁用级联删除来删除路径或通过将某些关系定义为可选(使用可空的外键,但不能配置与级联删除的关系)。

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

是真的,您同时拥有FK作为可选项,但两个关系都配置了级联删除,这就是为什么EF抛出这个异常。我的建议只有一个关系与级联删除。关于其他的关系,恐怕你必须手动做。例如,如果您选择 Footer 手动删除,那么当您要删除 ProjectPage 时,您必须将 Footer 属性设置为 null 。这里的问题是你可以在你的数据库中有孤儿。为了避免这种情况,您可以覆盖上下文中的 SaveChanges 来查找和删除孤儿:

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. 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. The problem here is you could have orphans in your DB. To avoid that, you can override the SaveChanges on your Context to find and delete orphans:

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

另一种方法可能是设置 FooterId 默认(Guid)值。由于您的PK属性( Id )的类型是 Guid ,它不是Identity,您必须设置在向DB添加 ProjectPage 之前的属性。因此,使用 default(Guid)设置 FooterId 是标记要删除的实体的另一种方法。如果您选择此变体,您的 SaveChanges 方法可能如下所示:

Another way could be setting the FooterId with the default(Guid) value. 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. So, setting the FooterId with default(Guid) is another way to mark that entity that you want to delete. If you choose this variant, your SaveChanges method could be as I show below:

 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 方法。

This way you can avoid call the Find method.

这篇关于实体框架级联删除 - FOREIGN KEY约束的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆