2014-04-30 92 views
1

是否可以使用觸發器實現on update cascade?我寫了下面的示例代碼(也http://sqlfiddle.com/#!6/d7298/1):通過SQL Server中的更新觸發器級聯外鍵軟刪除標誌

create table Parent 
(
    Id int not null, 
    IsDeleted bit not null, 
) 

alter table Parent add constraint PPK primary key (Id, IsDeleted) 

create table Child 
(
    Id int not null, 
    IsDeleted bit not null, 

    ParentId int not null, 
    ParentIsDeleted bit not null, 
) 

alter table Child add constraint CPK primary key (Id, IsDeleted) 
alter table Child add constraint CFK foreign key (ParentId, ParentIsDeleted) references Parent(Id, IsDeleted) 
go 

create trigger ParentAfterUpdate on Parent 
after update 
as 
begin 
    if update(IsDeleted) 
     update c set c.ParentIsDeleted = i.IsDeleted from Child c inner join Inserted i on c.ParentId = i.Id 
end 
go 

insert into Parent values(100,0) 

insert into Child values(1000,0,100,0) 

update Parent set IsDeleted = 1 

CFK約束拋出一個錯誤這是行不通的。我希望級聯軟刪除,以便只要父記錄被軟刪除,子記錄就會被軟刪除。

IsDeletedCFK可以讓我級聯更新到Child,但在高併發環境下,我相信它應該是可能的損壞的數據庫狀態,以結束:

在T0: 實體框架將父項加載到內存中。父不會被刪除。

在T1: 父是軟的另一個獨立的查詢

在T2刪除: EF插入一個子記錄,但由於IsDeleted不是外鍵的部分,有指向一個活躍的孩子刪除的父母。

回答

1

從關係的角度來看,你的PK是無效的,因爲它有一個子集,它是一個有效的PK本身(Id列)。它也將允許有兩個具有相同ID的行,但一個刪除,一個不是(我認爲這不是你以後的)。如果你真的想這樣做,我只需要在Id列上做一個PK,也許在Id, IsDeleted上是唯一的。你的FK可以引用任何獨特的密鑰,而不僅僅是PK。

另外,在聲明FK時使用on update cascade選項,它將負責更新ParentIsDeleted列,然後您需要一個觸發器傳播到'IsDeleted'。請參閱代碼:

create table Parent 
(
    Id int not null, 
    IsDeleted bit not null, 
) 

alter table Parent add constraint PPK primary key (Id) 
alter table Parent add constraint uq unique (Id, IsDeleted) 

create table Child 
(
    Id int not null, 
    IsDeleted bit not null, 

    ParentId int not null, 
    ParentIsDeleted bit not null, 
) 

alter table Child add constraint CPK primary key (Id, IsDeleted) 
alter table Child add constraint CFK foreign key (ParentId, ParentIsDeleted) references Parent(Id, IsDeleted) on update cascade 
go 


create trigger trChildUpdate 
on Child 
after update 
as 
select trigger_nestlevel(object_id('trChildUpdate'), 'AFTER', 'DML'); 
if ((select trigger_nestlevel(object_id('trChildUpdate'), 'AFTER', 'DML')) > 1) 
    return; 
update c 
set c.IsDeleted = i.ParentIsDeleted 
from Child c inner join Inserted i on c.Id = i.Id 
go 


insert into Parent values(100,0) 

insert into Child values(1000,0,100,0) 

update Parent set IsDeleted = 1 

select * from child 
+0

謝謝。我將採取獨特的索引方法。你能評論多少存儲空間分配給uq?它是每行4 + 1 = 5個字節嗎?我相信在非聚集索引中,索引鍵的大小與聚集索引的大小相結合。只是想知道需要多少額外空間來維護上述數據結構。 – Mark13426

+1

如果表被聚集在'Id'上,開銷很小。 NCI將包含來自CI的列,但不是兩次,這是正確的。 – dean