Sql server SQL Server引入外键约束可能会导致循环或多个级联路径

Sql server SQL Server引入外键约束可能会导致循环或多个级联路径,sql-server,Sql Server,我有两个表:用户表和订单表 T_订单必须向T_用户提供外键 然后我在我的图表上建立了两个关系,从T_用户ID到T_顺序的两个FK。我还将关系删除和更新规则都设置为级联,因为我想知道T_用户记录是否会被删除,因此T_顺序中的记录应该被删除,或者如果T_用户ID会发生变化,那么也会按T_顺序更新它。然而,我得到以下错误: “T_用户”表已成功保存“T_订单”表 -无法创建关系“FK\U T\U订单\U T\U用户1”。在表“T_Order”上引入外键约束“FK_T_Order_Users1”可能会

我有两个表:用户表和订单表

T_订单必须向T_用户提供外键

然后我在我的图表上建立了两个关系,从T_用户ID到T_顺序的两个FK。我还将关系删除和更新规则都设置为级联,因为我想知道T_用户记录是否会被删除,因此T_顺序中的记录应该被删除,或者如果T_用户ID会发生变化,那么也会按T_顺序更新它。然而,我得到以下错误:

“T_用户”表已成功保存“T_订单”表 -无法创建关系“FK\U T\U订单\U T\U用户1”。在表“T_Order”上引入外键约束“FK_T_Order_Users1”可能会 导致循环或多个级联路径。指定在删除时不执行任何操作或 更新时不执行任何操作,或修改其他外键约束。能够 不创建约束或索引。请参阅前面的错误

实数图: 由@Martin Brown链接的问题建议使用触发器而不是级联外键。下面是一个使用INSTEADOFDELETE触发器执行我认为您想要执行的操作的示例

-- Create tables
create table dbo.T_User (
    ID int identity not null primary key,
    Name varchar(100) not null
)

create table dbo.T_Order (
    ID int identity not null primary key,
    FK_UserActionOwnerID int not null,
    FK_UserActionReceiverID int not null
)
go

-- Create foreign keys
alter table dbo.T_Order add constraint FK_T_Order_T_Users1 FOREIGN KEY (FK_UserActionOwnerID) REFERENCES dbo.T_User (ID) 
alter table dbo.T_Order add constraint FK_T_Order_T_Users2 FOREIGN KEY (FK_UserActionReceiverID) REFERENCES dbo.T_User (ID) 
go

-- Create trigger
create trigger tr_T_User_Delete on dbo.T_User instead of delete as
begin

    if (@@rowcount = 0) return

    delete o from dbo.T_Order o inner join deleted d on d.ID = o.FK_UserActionOwnerID

    delete o from dbo.T_Order o inner join deleted d on d.ID = o.FK_UserActionReceiverID

    delete u from dbo.T_User u inner join deleted d on d.ID = u.ID  

end
go

-- Demo
insert dbo.T_User (Name) values ('Peter'), ('Paul') -- Assume identity ID 1 and 2

insert dbo.T_Order (FK_UserActionOwnerID, FK_UserActionReceiverID) values (1, 1), (1, 2), (2, 2)

select * from dbo.T_Order

delete from dbo.T_User where ID = 1

select * from dbo.T_Order

你可以用同样的方法来代替更新触发器,但是你可能想考虑一下更新ID是否有意义——我通常不会这么想。

可能重复@MartinBrown我读到了,但老实说,我不知道如何解决这个问题。就像T_Order有fk关于谁下了命令fk_UserActionOwnerID,但也有一个引用,这意味着我需要两个外键。还包括对cascae的删除/更新。如果我不能从一个表到另一个表进行两次引用,那么如何解决这个问题?通常的方法是先创建没有级联的FK约束,然后创建触发器,按照您希望的方式进行级联。@MartinBrown i上传了图表截图-看那里,我用红线标记了我想做的事情,但它会引发我描述的错误。那么您是说您不知道如何在没有在图表设计器中级联的情况下创建外键?t_Order和t_OrderItem呢?我是否应该保留这些表之间的连接,因为这意味着将删除/更新规则作为级联?@Eldorado是的,您可以在T_Order和T_OrderItem之间保留带有级联规则的FK,或者使用如上所述的触发器-这取决于您。我在删除所有更新/删除到无操作之前出现此错误,因此我不明白为什么会出现此错误::tr_T_User_delete,第1行[批处理开始行2]不能创建而不是删除,也不能在表“T_Users”上创建而不是更新触发器“tr_T_User_Delete2”。这是因为表中有一个带有级联删除或更新的外键。@Eldorado该错误很明显-您不能有一个代替。。。触发器以及在同一个表上具有级联操作的外键。我必须从头开始重新创建这两个表,然后再次创建它们并运行触发器脚本——现在它可以工作了。尽管如此,我现在看不到图表上这两个表之间的关系——我理解,因为现在并没有外键,只有外部触发器。我在这里看到了一个问题,让我们想象一下外部应用程序,并假设有人添加了用户id,以便不存在。因为我们没有fks,所以有可能,有什么解决办法吗?
T_Order
--------
ID
FK_UserActionOwnerID
FK_UserActionReceiverID
-- Create tables
create table dbo.T_User (
    ID int identity not null primary key,
    Name varchar(100) not null
)

create table dbo.T_Order (
    ID int identity not null primary key,
    FK_UserActionOwnerID int not null,
    FK_UserActionReceiverID int not null
)
go

-- Create foreign keys
alter table dbo.T_Order add constraint FK_T_Order_T_Users1 FOREIGN KEY (FK_UserActionOwnerID) REFERENCES dbo.T_User (ID) 
alter table dbo.T_Order add constraint FK_T_Order_T_Users2 FOREIGN KEY (FK_UserActionReceiverID) REFERENCES dbo.T_User (ID) 
go

-- Create trigger
create trigger tr_T_User_Delete on dbo.T_User instead of delete as
begin

    if (@@rowcount = 0) return

    delete o from dbo.T_Order o inner join deleted d on d.ID = o.FK_UserActionOwnerID

    delete o from dbo.T_Order o inner join deleted d on d.ID = o.FK_UserActionReceiverID

    delete u from dbo.T_User u inner join deleted d on d.ID = u.ID  

end
go

-- Demo
insert dbo.T_User (Name) values ('Peter'), ('Paul') -- Assume identity ID 1 and 2

insert dbo.T_Order (FK_UserActionOwnerID, FK_UserActionReceiverID) values (1, 1), (1, 2), (2, 2)

select * from dbo.T_Order

delete from dbo.T_User where ID = 1

select * from dbo.T_Order