我有 3 张桌子:
Compartment
、CompartmentRelation
和 CompartmentRelationType
。 CompartmentRelation 保留所选隔间周围的其他隔间(下方、上方、后面、前面等)。 CompartmentRelationType 保持位置。
我在 Compartment 中有名为 comp-1、comp-2、comp-3 和 comp-4 的隔间,并将 comp-1 上方的隔间插入 CompartmentRelation 中作为 comp-2 和 comp-3。
将 CompartmentRelation 表中的RelatedCompId 列的删除操作设置为级联会引发异常:
无法创建关系“FK_CompartmentRelation_Compartment1”
在表“CompartmentRelation”上引入 FOREIGN KEY 约束“FK_CompartmentRelation_Compartment1”可能会导致循环或多个级联路径。指定 ON DELETE NO ACTION 或 ON UPDATE NO ACTION,或修改其他 FOREIGN KEY 约束。
无法创建约束或索引。查看之前的错误。
我该怎么办?
CREATE TABLE [dbo].[Compartment] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[Name] NVARCHAR (500) NOT NULL,
CONSTRAINT [PK_Compartment] PRIMARY KEY CLUSTERED ([Id] ASC)
);
CREATE TABLE [dbo].[CompartmentRelation] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[CompId] INT NOT NULL,
[RelationTypeId] INT NOT NULL,
[RelatedCompId] INT NOT NULL,
CONSTRAINT [PK_CompartmentRelation] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_CompartmentRelation_CompartmentRelationType] FOREIGN KEY ([RelationTypeId]) REFERENCES [dbo].[CompartmentRelationType] ([Id]) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT [FK_CompartmentRelation_Compartment1] FOREIGN KEY ([RelatedCompId]) REFERENCES [dbo].[Compartment] ([Id]),
CONSTRAINT [FK_CompartmentRelation_Compartment] FOREIGN KEY ([CompId]) REFERENCES [dbo].[Compartment] ([Id]) ON DELETE CASCADE ON UPDATE CASCADE
);
CREATE TABLE [dbo].[CompartmentRelationType] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[Name] NVARCHAR (200) NOT NULL,
[NameLan1] NVARCHAR (200) NOT NULL,
[NameLan2] NVARCHAR (200) NULL,
CONSTRAINT [PK_CompartmentRelationType] PRIMARY KEY CLUSTERED ([Id] ASC));
问题在于将删除操作设置为列的级联 CompartmentRelation表中的RelatedCompId抛出异常为
无法建立关系 'FK_CompartmentRelation_Compartment1'。
介绍外键 表上的约束“FK_CompartmentRelation_Compartment1” “CompartmentRelation”可能会导致循环或多级联路径。 指定 ON DELETE NO ACTION 或 ON UPDATE NO ACTION,或修改其他 外键约束。无法创建约束或索引。 查看之前的错误。
基本问题似乎是从表
Compartment
中删除(并更新其 PK)可以通过两个不同的外键级联到 CompartmentRelation
。如果您打算支持与自身相关的隔间,那么从 Compartment
到 CompartmentRelation
级联的故事就结束了——您不能这样做。* 如果您打算禁止自我关系,那么您可以尝试向 CompartmentRelation
添加检查约束以强制执行该禁令,尽管我完全不确定 SQL Server 是否会考虑到这一点。
如果 SQL Server 不接受级联删除,那么您至少有三个选择:
让应用程序有责任在删除隔间之前清理隔间关系。 (并且不要级联。)
创建触发器以在删除隔间时处理关系删除。 (并且不要级联。)
创建一个用于删除隔间的存储过程,并使其处理所需的关系删除(不依赖级联)。
我该走哪条路?
其中哪一个对您的应用最有意义。都有优点和缺点。
此外,
不要级联更新代理键列,特别是当键值是机器生成的时,就像您的所有键值一样。这些密钥一开始就不应该更新,如果尝试更新密钥,那么数据库最好拒绝它(无论出于何种原因),而不是接受它。
您可能不想将
CompartmentRelationType
级联删除到 ComponentRelation
。包含这样的级联允许通过删除类型本身来删除给定类型的所有关系,但是这样的级联更可能是错误执行的,而不是有意执行的,如果错误执行,则导致的数据丢失将是严重的。最好让应用程序显式删除所有这些关系(如果这就是它真正的意思),否则拒绝删除现有关系正在使用的类型。
*从技术上讲,您可以通过仅从两个FK之一与
Compartment
进行级联来做到这一点,但这样的折衷措施似乎不太可能满足您的目的。