外键约束循环或多级联路径

问题描述 投票:0回答:1

我有 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));
sql sql-server foreign-keys primary-key
1个回答
0
投票

问题在于将删除操作设置为列的级联 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 不接受级联删除,那么您至少有三个选择:

  1. 让应用程序有责任在删除隔间之前清理隔间关系。 (并且不要级联。)

  2. 创建触发器以在删除隔间时处理关系删除。 (并且不要级联。)

  3. 创建一个用于删除隔间的存储过程,并使其处理所需的关系删除(不依赖级联)。

我该走哪条路?

其中哪一个对您的应用最有意义。都有优点和缺点。

此外,

  • 不要级联更新代理键列,特别是当键值是机器生成的时,就像您的所有键值一样。这些密钥一开始就不应该更新,如果尝试更新密钥,那么数据库最好拒绝它(无论出于何种原因),而不是接受它。

  • 您可能不想将

    CompartmentRelationType
    级联删除到
    ComponentRelation
    。包含这样的级联允许通过删除类型本身来删除给定类型的所有关系,但是这样的级联更可能是错误执行的,而不是有意执行的,如果错误执行,则导致的数据丢失将是严重的。最好让应用程序显式删除所有这些关系(如果这就是它真正的意思),否则拒绝删除现有关系正在使用的类型。


*从技术上讲,您可以通过仅从两个FK之一与

Compartment
进行级联来做到这一点,但这样的折衷措施似乎不太可能满足您的目的。

© www.soinside.com 2019 - 2024. All rights reserved.