如何在有周期和多个级联路径的地方配置级联删除

时间:2019-07-12 02:47:05

标签: c# asp.net-core .net-core orm entity-framework-core

我在解决这种关系时遇到了麻烦,以及如何为此设置级联删除设置。

  • 有一张员工表,其中每个员工都有任意数量的手柄,附件和工作
  • 有一个句柄表,其中每个句柄都属于一个雇员,可以在工具中使用
  • 有一个附件表,其中每个附件都属于一个雇员,可以在工具中使用
  • 有一张工具表,其中每个工具都由一个附件,一个手柄组成,并且可用于任何数量的工作
  • 有一张工作表,其中每个工作都属于一个雇员,并且可能使用或可能不使用工具

注意:句柄和附件可能存在而没有用于制作工具

简而言之:员工可以混合使用手柄和附件来制作工具,然后在分配给他们的工作中使用工具。

此图显示了数据库如何连接在一起(建议更好的设计

DB Diagram

这是模型的设置方式,Job模型具有对工具FK(ToolId)的可空引用,因此无需工具即可存在作业。

public class Employee
{
    public int EmployeeId { get; set; }
    public string Name { get; set; }

    public List<Handle> Handles { get; set; }
    public List<Attachment> Attachments { get; set; }
    public List<Job> Jobs { get; set; }
}
public class Handle
{
    public int HandleId { get; set; }
    public string Material { get; set; }
    public double ExpectedLife { get; set; }
    public double LifetimeMaintenance { get; set; }

    public int EmployeeId { get; set; }
    public Employee Employee { get; set; }
    public List<Tool> Tools { get; set; }
}
public class Attachment
{
    public int AttachmentId { get; set; }
    public string Material { get; set; }
    public string Type { get; set; }
    public double ExpectedLife { get; set; }
    public double LifetimeMaintenance { get; set; }

    public int EmployeeId { get; set; }
    public Employee Employee { get; set; }
    public List<Tool> Tools { get; set; }
}
public class Tool
{
    public int ToolId { get; set; }
    public string OperationSpeed { get; set; }


    public int HandleId { get; set; }
    public Handle Handle { get; set; }

    public int AttachmentId { get; set; }
    public Attachment Attachment { get; set; }

    public List<Job> Jobs { get; set; }
}
public class Job
{
    public int JobId { get; set; }
    public string Name { get; set; }
    public double EffortRequired { get; set; }

    public int EmployeeID { get; set; }
    public Employee Employee { get; set; }
    public int? ToolId { get; set; }
    public Tool Tool { get; set; }
}

这是创建数据库上下文的方式。有一个级联删除设置,用于在删除工具时将“作业”中的工具FK(ToolId)设置为null(因此,在删除其工具时不会删除该作业)。

public class ToolsDbContext : DbContext
{
    public ToolsDbContext(DbContextOptions<ToolsDbContext> options) : base(options)
    {

    }

    public DbSet<Employee> employees { get; set; }
    public DbSet<Handle> handles { get; set; }
    public DbSet<Attachment> attachments { get; set; }
    public DbSet<Tool> tools { get; set; }
    public DbSet<Job> jobs { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Tool>()
            .HasMany(j => j.Jobs)
            .WithOne(t => t.Tool)
            .OnDelete(DeleteBehavior.SetNull);
    }
}

创建迁移有效,但是随后更新数据库失败,并显示以下错误:

Introducing FOREIGN KEY constraint 'FK_tools_handles_HandleId' on table 'tools' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Could not create constraint or index. See previous errors.

我不太确定如何理解此错误。

通过以下方式进行思考:

  • 如果删除了句柄,它将删除它所使用的所有工具,从而将相关Jobs中的ToolId设置为null
  • 如果附件被删除,它将删除其使用的所有工具,从而将相关作业中的ToolId设置为null
  • 如果删除工具,则会将相关作业中的ToolId设置为null
  • 如果删除作业,则不会产生级联效果

因此,我认为问题一定出在删除雇员上,但是我不明白为什么(还?)...

  • 如果删除员工,则应删除所有内容;它应该删除所有相关的作业,句柄和附件。然后,那些删除的句柄或附件应依次删除与它们相关联的工具(无关紧要的是什么)。

因此,有级联路径删除雇员,但是我希望这一切都将照原样在模型设置的基础上起作用。...我是否需要在dbcontext中配置更多级联删除要求?如果是这样,我不确定应该如何配置...

注意:如果数据库中没有员工模型,一切似乎都可以正常工作

2 个答案:

答案 0 :(得分:1)

SQL Server不允许在数据库中具有指向同一表的多个级联路径。在您的情况下,其中有两个工具:

  • 员工->处理->工具
  • 员工->附件->工具

解决此问题的所有方法都包括为一个关系或另一个关系设置DeleteBehavior.Restrict,例如:

  • 为实体设置DeleteBehavior.Restrict->通过触发器处理关系并处理此级联路径(否则“ restrict”将不允许删除对其引用的记录)
  • 为实体设置DeleteBehavior.Restrict->处理关系并在应用程序代码中处理此级联路径(在删除主要实体之前,显式更新/删除所有相关实体)
  • 设置两个实体关系的“限制”行为

等...

答案 1 :(得分:0)

您说:

  

有一张员工表,其中每个员工都有任意数量的手柄,附件和作业

但是您的图表在员工和一个手柄之间建立了直接链接,一个手柄有很多员工,而一个员工只有一个手柄

您的陈述与您的图表冲突

从数据库的角度来看,我认为这种建模是错误的。我认为工作应该有雇员。 (如果一个工作有多个雇员,则需要另一个表雇员将一个工作ID映射到多个雇员。)一个工作有一个工具,一个工具有一个手柄和一个附件。我看不到为什么删除员工应该删除他们的工作(如果我解雇了某人,但他为我工作时盖的房子仍然存在),但是您可以在不使用级联约束的情况下进行清理

最终,您可以在图中看到已创建的循环。如果删除1端的内容会删除*端的所有内容,则删除图表中的任何内容都会启动一条链,该链采用一条分离的路径,该路径会重新组合在一起。删除员工实体确实可以解决这个问题

最终,员工不应直接拥有工作,把手或附件