在我的数据库中,有两个表:[Node]
和[NodeDetail]
。
[节点]:
CREATE TABLE [dbo].[Node]
(
[ID] UNIQUEIDENTIFIER DEFAULT (newid()) NOT NULL,
[Name] NVARCHAR (100) NOT NULL,
[Description] NVARCHAR (MAX) NULL,
[NodeTypeID] UNIQUEIDENTIFIER NOT NULL,
CONSTRAINT [pk_Node] PRIMARY KEY NONCLUSTERED ([ID]),
CONSTRAINT [fk_Node_NodeTypeID]
FOREIGN KEY ([NodeTypeID]) REFERENCES [dbo].[NodeType] ([ID])
ON DELETE NO ACTION ON UPDATE CASCADE,
CONSTRAINT [pk_NodeName] UNIQUE CLUSTERED ([Name] ASC, [NodeTypeID] ASC)
);
CREATE NONCLUSTERED INDEX [ix_Node_NodeTypeID]
ON [dbo].[NodeType]([NodeTypeID] ASC);
[NodeDetail]:
CREATE TABLE [dbo].[NodeDetail]
(
[ID] UNIQUEIDENTIFIER DEFAULT (newid()) NOT NULL,
[ParentNodeID] UNIQUEIDENTIFIER NOT NULL,
[ChildNodeID] UNIQUEIDENTIFIER NULL,
[UnimportantProperty] INT NULL,
[ImportantProperty] DECIMAL (19, 6) DEFAULT ((0)) NOT NULL,
…
CONSTRAINT [pk_NodeDetail] PRIMARY KEY CLUSTERED ([ID] ASC),
CONSTRAINT [fk_NodeDetail_ChildNodeID]
FOREIGN KEY ([ChildNodeID]) REFERENCES [dbo].[Node] ([ID])
ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT [fk_NodeDetail_ParentNodeID]
FOREIGN KEY ([ParentNodeID]) REFERENCES [dbo].[Node] ([ID])
ON DELETE CASCADE ON UPDATE CASCADE
);
CREATE NONCLUSTERED INDEX [ix_NodeDetail_ParentNodeID]
ON [dbo].[NodeDetail]([ParentNodeID] ASC);
CREATE NONCLUSTERED INDEX [ix_NodeDetail_ChildNodeID]
ON [dbo].[NodeDetail]([ChildNodeID] ASC);
当我尝试部署到Azure中的真实数据库时,它开始抱怨fk_NodeDetail_ChildNodeID
可能导致循环或多个级联路径
现在,我正试图看看这些周期可能发生的地方以及如何打破它们,但我无法识别。
据我了解,删除[dbo].[Node] where [ID] = 1
后,[dbo].[NodeDetail] where [ChildNodeID] = 1
中的所有条目都将被删除。同时,[dbo].[NodeDetail] where [ParentNodeID] = 1
中的所有条目也将被删除。
[dbo].[NodeDetail]
中的任何属性都不是任何其他表中的外键,因此我不明白它可以传播到何处。
整个事物展开成一棵树。目标是确保每当删除节点或更改其ID(可能发生)时,将相应地删除或更新将其连接到另一个节点的节点详细信息。 NodeDetail
上有一个ID,因为在两个不同的节点之间可能存在多个具有不同属性的NodeDetail
。
编辑:
所以我找到了原因,即两个FK在同一个表中引用相同的列。在SQL Server的思想中,当两者都指向同一条目时,更改该条目可能需要更改两个FK。通过一些不可思议的逻辑,这意味着一个循环或多个级联路径。
坏消息:这不是由CHECK约束修复的(如果你的版本支持它)。要将树折叠到数据库中,必须使用过程和触发器来消除垃圾。