在 parent 被删除时删除 child 行的最简单方法是什么,而不知道它的 parent 是什么?

What is the simplest way to delete a child row when its parent is deleted, without knowing what its parent is?

给定多个实体类型:

  1. Cluster
  2. Hypervisor
  3. VirtualMachine

并给出可能属于其中任何一个的属性(但每行不超过一个):

删除 属性 及其 parent 的最简单方法是什么?

尝试的解决方案

ON DELETE CASCADE

ON DELETE CASCADE 似乎每个可能的 parent 都需要一个可为空的外键,这让我觉得这是一个糟糕的设计:

CREATE TABLE CpuInfo
(
    -- Properties
    Id INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
    CpuSpeed INT,
    AllocatedTotal INT,
    CpuTotal INT,
    AvailableTotal INT,

    -- Foreign keys for all possible parents
    ClusterId INT,
    HypervisorId INT,
    VirtualMachineId INT,

    FOREIGN KEY (ClusterId) REFERENCES Cluster(Id) ON DELETE CASCADE,
    FOREIGN KEY (HypervisorId) REFERENCES Hypervisor(Id) ON DELETE CASCADE,
    FOREIGN KEY (VirtualMachineId) REFERENCES VirtualMachine(Id) ON DELETE CASCADE
);

带触发器的联结表

Parents 通过连接表与属性相关。例如:

CREATE TABLE HypervisorCpuInfo
(
    HypervisorId INT NOT NULL,
    CpuInfoId INT NOT NULL,

    FOREIGN KEY (HypervisorId) REFERENCES Hypervisor(Id),
    FOREIGN KEY (CpuInfoId) REFERENCES CpuInfo(Id) ON DELETE CASCADE
);

每个实体类型都有一个 DELETE 触发器。触发器选择实体属性的 ID 并将其删除。删除属性后,child 连接行也会通过 ON CASCADE DELETE.

删除

不过,这并不能很好地模拟业务规则,因为它允许相同的 CpuInfo 属于多个实体。它还在设计中增加了很多表格。

有没有更简单的解决方案?

我认为 "junction table" 可能适合 DRYness(由于 1:n 关系,它不是真正的交汇点)

你可以称你的 "junction table" 为 "super table"(类似于 "machine" [对不起,我不是本地人]):

在此 table 中,您将所有键放入您的属性(使每个外键列唯一以确保 1:1*)。您的 "machine" (Cluster,Hypervisor,VirtualMachine) 的类型在您已经尝试过的 "triple key" 中 - 也在超级 [=35= 中]. 为确保 "machine" 仅属于一个实体,请添加约束:

ALTER TABLE CpuInfo WITH CHECK ADD CONSTRAINT [CK_keyIDs] CHECK (
(ClusterId IS NULL AND HypervisorId IS NULL AND VirtualMachineId IS NOT NULL)
OR (ClusterId IS NULL AND HypervisorId IS NOT NULL AND VirtualMachineId IS NULL)
OR (ClusterId IS NOT NULL AND HypervisorId IS NULL AND VirtualMachineId IS NULL)) GO

好处是你对你的实体很自由,你可以允许 PC 同时成为 Cluster

*关键一栏! ID 必须是唯一的