我有一个Transaction(Id,Comment,ClosingTransactionId)表。我希望在删除时实现“设置为空”功能。
所以如果我有两行:
(1,开始交易,2)
(2,完成交易,为空)
,然后删除第二行,然后将第一行的ClosingTransactionId设置为null。我可以使用“无操作”向ClosingTransactionId添加外键约束,但不能通过“ set null”添加外键约束,因为SQL Server会引发“循环或多个级联路径”。
有些页面解释了问题,https://stackoverflow.com/a/12683993/5852947,有些则建议使用触发器,https://stackoverflow.com/a/852047/5852947,另一些则说什么比触发器更好。我应该走哪条路? (当然,我可以将第一行的ClosingTransactionId设置为null,然后删除第二行,但我真的希望数据库能够处理此问题。)
如果有帮助,我会使用EF6。
答案 0 :(得分:2)
我真的希望Db能够解决这个问题
然后,您需要一个INSTEAD OF DELETE触发器。在许多情况下,SQL Server禁止使用级联删除,而在其他情况下,级联删除是有意义的,部分原因是您始终可以使用触发器来实现该行为。
它们不是邪恶的,只是容易出错。
例如
use tempdb
drop table if exists [transaction]
go
create table [Transaction]
(
Id int primary key,
Comment nvarchar(200),
ClosingTransactionId int null references [Transaction]
)
insert into [Transaction]
values (1,'opening transactin',null),(2,'closing transaction',null)
update [Transaction] set ClosingTransactionId = 2 where id = 1
delete from [Transaction] where id = 2
--Msg 547, Level 16, State 0, Line 17
--The DELETE statement conflicted with the SAME TABLE REFERENCE constraint "FK__Transacti__Closi__29572725". The conflict occurred in database "tempdb", table "dbo.Transaction", column 'ClosingTransactionId'.
go
create or alter trigger TransactionDelete
on [Transaction]
instead of delete
as
begin
set nocount on
update [Transaction] set ClosingTransactionId = null
where ClosingTransactionId in (select id from deleted)
delete from [Transaction]
where id in (select id from deleted)
end
go
delete from [Transaction] where id = 2
--(1 row affected)
对于EF,您仍然应该为级联删除配置模型,但是要阻止它尝试在数据库中创建外键。您将无需级联删除就可以创建并添加触发器。
答案 1 :(得分:0)
您可以采用不同的设计来代替自引用FK,以避免出现多个级联路径并避免触发。
下面的SO帖子使我有了这个主意: https://stackoverflow.com/a/3548225/634935
TransactionReferenceTable
+------------------------------------------------------------------------+
| TransactionReferenceId (PK) |
+------------------------------------------------------------------------+
| 1 |
| 2 --> Deleting this transaction will lead to child being set as NULL |
| 3 |
+------------------------------------------------------------------------+
TransactionDetailTable
+-------------------------+--------------------------+--------------------------------------------------------------+
| TransactionSurrogateKey | OpeningTransactionId(FK) | ClosingTransactionId (FK) |
+-------------------------+--------------------------+--------------------------------------------------------------+
| 1 | 1 | 2 --> On deletion of transaction ref, it will be set as null |
+-------------------------+--------------------------+--------------------------------------------------------------+