рекурсивный триггер удаления и ограничения ON DELETE CASCADE не удаляют все - PullRequest
1 голос
/ 26 ноября 2011

У меня есть очень простая модель данных, которая представляет древовидную структуру:

RootEntity является корнем такого дерева, оно может содержать дочерние элементы типа ContainerEntity и типа AtomEntity. Тип ContainerEntity также может содержать дочерние элементы типа ContainerEntity и типа AtomEntity, но не может содержать дочерние элементы типа RootEntity. На детей ссылаются в хорошо известном порядке. Модель БД для этого приведена ниже.

Моя проблема в том, что когда я удаляю RootEntity, я хочу, чтобы все дочерние элементы были удалены рекурсивно. У меня есть внешний ключ с CASCADE DELETE и два триггера удаления для этого. Но он не удаляет все, он всегда оставляет некоторые элементы в таблицах ContainerEntity, AtomEntity, ContainerEntity_Children и AtomEntity_Children. Кажется, начиная с уровня рекурсии 3.

CREATE TABLE RootEntity
(
    Id UNIQUEIDENTIFIER NOT NULL,
    Name VARCHAR(500) NOT NULL,

    CONSTRAINT PK_RootEntity PRIMARY KEY NONCLUSTERED (Id), 
);

CREATE TABLE ContainerEntity
(
    Id UNIQUEIDENTIFIER NOT NULL,
    Name VARCHAR(500) NOT NULL,

    CONSTRAINT PK_ContainerEntity PRIMARY KEY NONCLUSTERED (Id),    
);

CREATE TABLE AtomEntity
(
    Id UNIQUEIDENTIFIER NOT NULL,
    Name VARCHAR(500) NOT NULL,

    CONSTRAINT PK_AtomEntity PRIMARY KEY NONCLUSTERED (Id), 
);

CREATE TABLE RootEntity_Children
(
    ParentId UNIQUEIDENTIFIER NOT NULL,
    OrderIndex INT NOT NULL,
    ChildContainerEntityId UNIQUEIDENTIFIER NULL,
    ChildAtomEntityId UNIQUEIDENTIFIER NULL,
    ChildIsContainerEntity BIT NOT NULL,

    CONSTRAINT PK_RootEntity_Children 
        PRIMARY KEY NONCLUSTERED (ParentId, OrderIndex),

    -- foreign key to parent RootEntity
    CONSTRAINT FK_RootEntiry_Children__RootEntity
        FOREIGN KEY (ParentId) REFERENCES RootEntity (Id)
        ON DELETE CASCADE,

    -- foreign key to referenced (child) ContainerEntity    
    CONSTRAINT FK_RootEntiry_Children__ContainerEntity
        FOREIGN KEY (ChildContainerEntityId) REFERENCES ContainerEntity (Id)
        ON DELETE CASCADE,

    -- foreign key to referenced (child) AtomEntity
    CONSTRAINT FK_RootEntiry_Children__AtomEntity
        FOREIGN KEY (ChildAtomEntityId) REFERENCES AtomEntity (Id)
        ON DELETE CASCADE,
);

CREATE TABLE ContainerEntity_Children
(
    ParentId UNIQUEIDENTIFIER NOT NULL,
    OrderIndex INT NOT NULL,
    ChildContainerEntityId UNIQUEIDENTIFIER NULL,
    ChildAtomEntityId UNIQUEIDENTIFIER NULL,
    ChildIsContainerEntity BIT NOT NULL,

    CONSTRAINT PK_ContainerEntity_Children 
        PRIMARY KEY NONCLUSTERED (ParentId, OrderIndex),

    -- foreign key to parent ContainerEntity
    CONSTRAINT FK_ContainerEntity_Children__RootEntity
        FOREIGN KEY (ParentId) REFERENCES ContainerEntity (Id)
        ON DELETE CASCADE,

    -- foreign key to referenced (child) ContainerEntity    
    CONSTRAINT FK_ContainerEntity_Children__ContainerEntity
        FOREIGN KEY (ChildContainerEntityId) REFERENCES ContainerEntity (Id)
        ON DELETE CASCADE,

    -- foreign key to referenced (child) AtomEntity
    CONSTRAINT FK_ContainerEntity_Children__AtomEntity
        FOREIGN KEY (ChildAtomEntityId) REFERENCES AtomEntity (Id)
        ON DELETE CASCADE,
);

CREATE TRIGGER Delete_RootEntity_Children ON RootEntity_Children FOR DELETE
AS
DELETE FROM ContainerEntity WHERE Id IN (SELECT ChildContainerEntityId FROM deleted)
DELETE FROM AtomEntity WHERE Id IN (SELECT ChildAtomEntityId FROM deleted)
GO

CREATE TRIGGER Delete_ContainerEntiy_Children ON ContainerEntity_Children FOR DELETE
AS
DELETE FROM ContainerEntity WHERE Id IN (SELECT ChildContainerEntityId FROM deleted)
DELETE FROM AtomEntity WHERE Id IN (SELECT ChildAtomEntityId FROM deleted)
GO

1 Ответ

1 голос
/ 26 ноября 2011

Попытка без триггеров:

Entity
Id 
Name
PRIMARY KEY (id)

ParentEntity                  --- Root or Container
Id 
PRIMARY KEY (id)
FOREIGN KEY (Id) REFERENCES Entity (Id)
            ON DELETE CASCADE

ChildEntity                   --- Container or Atom
Id
ParentId
OrderIndex 
PRIMARY KEY (Id)
UNIQUE KEY (ParentId, OrderIndex)
FOREIGN KEY (Id) REFERENCES Entity (Id)
            ON DELETE CASCADE
FOREIGN KEY (ParentId) REFERENCES ParentEntity (Id)
            ON DELETE CASCADE

и остальные:

RootEntity
Id 
PRIMARY KEY (Id)
FOREIGN KEY (Id) REFERENCES ParentEntity (Id)         --- it is a Parent
            ON DELETE CASCADE

ContainerEntity
Id 
PRIMARY KEY (Id)
FOREIGN KEY (Id) REFERENCES ParentEntity (Id)         --- it is a Parent
            ON DELETE CASCADE
FOREIGN KEY (Id) REFERENCES ChildEntity (Id)          --- and a Child
            ON DELETE CASCADE

AtomEntity
Id
PRIMARY KEY (Id)
FOREIGN KEY (Id) REFERENCES ChildEntity (Id)          --- it is a Child
            ON DELETE CASCADE
...