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 で: Entity Framework が親をメモリに読み込みます。親は削除されません。

T1 で: 親は別の独立したクエリによって論理的に削除されます

T2 で: EF は子レコードを挿入しIsDeletedますが、外部キーの一部ではないため、削除された親を指すアクティブな子があります。

4

1 に答える 1

1

リレーショナルの観点からは、有効な PK 自体 (Id列) であるサブセットがあるため、PK は有効ではありません。また、同じIDを持つ2つの行を持つこともできますが、1つは削除され、もう1つは削除されません(これはあなたが求めているものではないと思います)。あなたが本当にこの道を行きたいのなら、私はId列だけに PK を作り、おそらくユニークにId, IsDeleted. FK は、PK だけでなく、任意の一意のキーを参照できます。

on update cascadeさらに、 FK を宣言するときにオプションを使用する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 に答える