2014-04-30 4 views
1

트리거를 사용하여 on update cascade을 구현할 수 있습니까? CFK 제약에서 오류가 발생으로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 

이 작동하지 않습니다 나는 (또한 http://sqlfiddle.com/#!6/d7298/1)에 다음 예제 코드를 썼다. 상위 레코드가 소프트 삭제 될 때마다 하위 레코드가 소프트 삭제되도록 소프트 삭제를 계단식으로 배열하기를 바랬습니다. CFK에서 IsDeleted 촬영

Child 아래로 업데이트를 계단식으로 허용 할 수 있지만, 고도의 동시성 환경에서, 나는 손상된 데이터베이스 상태로 끝날 수 있어야한다 생각 : T0에서

: 를 Entity Framework는 부모를 메모리로로드합니다. 부모는 삭제되지 않습니다. T1에서

: 부모 소프트 다른 독립적 인 쿼리 T2에서

에 의해 삭제 : EF 아이의 기록을 삽입하지만, IsDeleted이 외부 키의 일부가 아닌 때문에, 가리키는 활성 아이가 삭제 된 부모.

답변

1

관계형으로 볼 때 PK는 유효한 PK 자체 (Id 열)의 하위 집합이 있으므로 유효하지 않습니다. 또한 동일한 ID를 가진 두 개의 행을 가질 수 있지만 하나는 삭제되고 하나는 삭제되지 않습니다. 이 방법으로 정말로 가고 싶다면 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 
+0

감사합니다. 고유 한 색인 접근 방식을 사용하겠습니다. 당신은 uq에 할당 된 저장 공간의 크기에 대해 언급 할 수 있습니까? 그것은 4 + 1 = 행당 5 바이트입니까? 비 클러스터형 인덱스는 클러스터형 인덱스의 크기와 결합 된 인덱스 키의 크기입니다. 위의 데이터 구조를 유지하는 데 얼마나 많은 공간이 필요한지 알고 싶습니다. – Mark13426

+1

테이블이'Id'에 클러스터되어 있으면 오버 헤드가 거의 없습니다. NCI에는 CI의 열이 포함되지만 두 번 열은 포함되지 않는 것이 맞습니다. – dean