简体   繁体   English

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

[英]How to configure cascade delete where there are cycles and multiple cascade paths

I'm having a bit of trouble getting my head around this relationship, and how to possibly setup cascade delete settings for it. 我很难理解这种关系,以及如何为它设置级联删除设置。

  • There is a table of employees, where each employee has any number of handles, attachments and jobs 有一张员工表,其中每个员工都有任意数量的手柄,附件和作业
  • There is a table of handles, where each handle belongs to an employee and may be used in a tool 有一张表的句柄,其中每个句柄都属于一个雇员,可以在工具中使用
  • There is a table of attachments, where each attachment belongs to an employee and may be used in a tool 有一个附件表,其中每个附件都属于一个雇员,可以在工具中使用
  • There is a table of tools, where each tool is made up of one attachment, one handle and is used on any number of jobs 有一张工具表,其中每个工具由一个附件,一个手柄组成,可用于任何数量的作业
  • There is a table of jobs, where each job belongs to an employee, and may or may not have a tool used on it 有一张工作表,其中每个工作都属于一个员工,并且可能使用或可能不使用工具

Note: it's possible for handles and attachments to exist without being used to make a tool 注意:句柄和附件可能存在而没有用于制作工具

In short: an employee can mix-and-match handles and attachments to make tools, and then use a tool on a job they are assigned. 简而言之:员工可以混合使用手柄和附件来制作工具,然后在分配给他们的工作中使用工具。

This diagram shows how the database is wired together ( feel free to suggest a better design ) 该图显示了数据库是如何连接在一起的(可以随时提出更好的设计建议

DB Diagram 数据库图

This is how the models are setup, the Job model has a nullable reference to the tools FK (ToolId) so a job can exist without a tool. 这就是模型的设置方式,“作业”模型对工具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; }
}

This is how the DB context has been created. 这就是创建数据库上下文的方式。 There is a cascade delete setting to set the tool FK in Jobs (ToolId) to null when a tool is deleted (so the job wont get deleted when its tool is deleted). 有一个级联删除设置,用于在删除工具时将“作业”中的工具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);
    }
}

Creating the migration works, but then updating the database fails with the following error: 创建迁移是可行的,但是随后更新数据库失败,并显示以下错误:

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.

I'm not too sure how to understand this error. 我不太确定如何理解此错误。

Thinking it through: 通过以下方式进行思考:

  • If a handle is deleted, it will delete all tools it's used in, which in turn will set ToolId in related Jobs to null 如果删除了句柄,它将删除它使用的所有工具,从而将相关Jobs中的ToolId设置为null
  • If an attachment is deleted, it will delete all tools it's used in, which in turn will set ToolId in related Jobs to null 如果附件被删除,它将删除其使用的所有工具,从而将相关Jobs中的ToolId设置为null
  • If a tool is deleted it will set ToolId in related Jobs to null 如果删除工具,则会将相关作业中的ToolId设置为null
  • If a job is deleted, there will be no cascade effect 如果删除作业,则不会产生级联效果

Therefore I think the problem must be with deleting an employee, but I can't see why (yet?)... 因此,我认为问题一定出在删除雇员上,但是我不明白为什么(还?)...

  • If an employee is deleted everything should be deleted; 如果删除员工,则应删除所有内容; it should delete all related jobs, handles and attachments. 它应该删除所有相关的作业,句柄和附件。 Then those deleted handles or attachments should in turn delete the tools associated with them (it shouldn't matter what came first). 然后,那些删除的句柄或附件应依次删除与它们相关联的工具(无关紧要的是什么)。

So there is cascade paths deleting an employee, but I would expect this would all work based on the model setup as-is... So do I need to configure more cascade delete requirements in the dbcontext? 因此,有一些级联路径删除了一个雇员,但是我希望这一切都将根据模型设置保持原样。 If so, I'm not sure how it should be configured... 如果是这样,我不确定应该如何配置...

Note: without the employees model in the database, everything seems to work 注意:如果数据库中没有员工模型,一切似乎都可以正常工作

SQL server doesn't allow to have multiple cascade paths to the same table in the database. SQL Server不允许在数据库中具有指向同一表的多个级联路径。 In your case there are two of them for Tools: 在您的情况下,其中有两个工具:

  • Employee -> Handle -> Tool 员工->处理->工具
  • Employee -> Attachment -> Tool 员工->附件->工具

All ways to fix the issue consist in setting DeleteBehavior.Restrict for one relationship or the other, for example: 解决此问题的所有方法都包括为一个关系或另一个关系设置DeleteBehavior.Restrict,例如:

  • Setting DeleteBehavior.Restrict for Entity -> Handle relationship and handling this cascade path by a trigger (otherwise "restrict" won't allow to delete a record having references to it) 为实体设置DeleteBehavior.Restrict->处理关系并通过触发器处理此级联路径(否则“ restrict”将不允许删除对其引用的记录)
  • Setting DeleteBehavior.Restrict for Entity -> Handle relationship and handling this cascade path in application code (update/delete all related entities explicitly before deleting the main one) 为实体设置DeleteBehavior.Restrict->处理关系并在应用程序代码中处理此级联路径(在删除主要实体之前,显式更新/删除所有相关实体)
  • Setting "restrict" behavior for both Entity relationships 为两个实体关系设置“限制”行为

etc... 等等...

You said: 你说:

There is a table of employees, where each employee has any number of handles, attachments and jobs 有一张员工表,其中每个员工都有任意数量的手柄,附件和作业

But your diagram establishes a direct link between an employee and a handle, one handle has many employees, and an employee has only one handle 但是您的图在一个员工和一个手柄之间建立了直接链接,一个手柄有很多员工,而一个员工只有一个手柄

Your statement is in conflict with your diagram 您的陈述与图表冲突

I think this modelling is wrong, from the database perspective. 从数据库的角度来看,我认为这种建模是错误的。 I think a job should have an employee. 我认为工作应该有雇员。 (If a job has multiple employees you'll need another table jobemployees that maps one job id to multiple employees.) A job has a tool, a tool has a handle and an attachment. (如果一个工作有多个雇员,则需要另一个表雇员将一个工作ID映射到多个雇员。)一个工作有一个工具,一个工具有一个手柄和一个附件。 I fail to see why deleting an employee should delete their jobs (if I fired someone the house he built while working for me still exists) but you can clean this up without using cascading constraints 我看不到为什么删除雇员应该删除他们的工作(如果我解雇了某人,但他为我工作时盖的房子仍然存在),但是您可以在不使用级联约束的情况下进行清理

Ultimately you can see in the diagram the cycle you've created. 最终,您可以在图中看到已创建的循环。 If deleting something at a 1 end deletes everything at the * end then deleting anything in your diagram starts a chain that takes a split path that comes back together. 如果删除1端的内容会删除*端的所有内容,则删除图表中的任何内容都会启动一条链,该链采用一条分离的路径,该路径会重新组合在一起。 Removing the employee entity does indeed break this up 删除员工实体确实可以解决这个问题

Ultimately an employee should not directly have a job, a handle or an attachment 最终,员工不应直接拥有工作,把手或附件

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM