1

是否可以on update cascade使用触发器来实现?我编写了以下示例代码(也在http://sqlfiddle.com/#!6/d7298/1上):

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约束会引发错误。我希望级联软删除,以便在软删除父记录时软删除子记录。

IsDeleted取出CFK可以让我将更新级联到Child,但在高度并发的环境中,我相信应该有可能以损坏的数据库状态结束:

在 T0:实体框架将父级加载到内存中。没有删除父级。

在 T1:父级被另一个独立查询软删除

在 T2:EF 插入一条子记录,但由于IsDeleted不是外键的一部分,因此有一个活动子记录指向已删除的父记录。

4

1 回答 1

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
于 2014-04-30T07:30:38.003 回答