我有表variable
和variable_variable
,最后一个表包含2列:
variable_id_from
variable_id_from
请看下面的模式:
如果variable_variable
包含值为{variable_id_from = 1, variable_id_to = 2}
的行,则意味着具有id = 1
的variable
引用了具有id = 2
的variable
。
现在我有了一个新的业务需求:
假设我们有variable A
,如果有任何其他variables
引用A
(即variable_variable
有任何值为{variable_id_to = A.id}
的行),则必须禁止删除A
。
假设我们有variable B
,如果没有变量引用B
,但同时B
引用任何其他变量,则删除B
应成功进行,并且删除{variable_id_from = B.id}
的所有引用。
我想创建一个简单的约束和级联删除。看看下面的SQL片段:
ALTER TABLE variable_variable
ADD CONSTRAINT variable_variable_variable_id_from_fkey
FOREIGN KEY (variable_id_from) REFERENCES variable (id)
ON DELETE CASCADE;
ALTER TABLE variable_variable
ADD CONSTRAINT variable_variable_variable_id_from_fkey
FOREIGN KEY (variable_id_to) REFERENCES variable (id);
我原以为它能完全满足我的需求,但奇怪的是,这个测试用例没有通过:
1.创建变量A
1.创建变量B
1.使A
成为B
的参考
1.尝试删除path2.net
1.预期:删除变量时出错。实际值:B
和variable_variable
中的所有对应链路已成功删除。
奇怪,好像variable_variable_variable_id_from_fkey
被触发了,有什么办法解决这个问题吗?
另外还有一个重要的情况,变量可能会引用自己,那么variable_variable
表可以包含行{variable_id_from = 1, variable_id_to = 1}
,这种情况下删除也应该成功通过,需要级联删除所有的链接。
另外,我知道我可以在应用程序端执行删除操作,但我认为这个决定是最后的选择。整个数据库结构比我展示的要复杂得多。级联约束确实有助于保持代码的整洁。
3条答案
按热度按时间qvtsj1bj1#
一个外键将与deleet上的加法级联,同时删除桥表中的所有记录
BEFORE DELETE TRIGGER将执行此操作,因为它将检查每个删除的行(如果variable_variable中有记录
参见示例
x一个一年零一年零一年零一年零一年零一年零一年零一年零一年零一年零二年零一年零一年零一年零三年零一年零一年零一年零四年零一年零一年零一年零一年零六年零一年零一年零一年零一年零一年零一年零一年零一年零一年零一年零一年零一年零一年零一年零一年零一年零一年零一年零一年零一年零一年零一年零一年零三年零一年零一年零一年零一年零一年零一年零一年零一年零一年零三年零一年零一年零一年零一年零一年零一年零一年零一年零一年零一年零一年零一年零一年零一年零一年零一年零一年零一年零一年零一年零一年零一年零一年零一年零一
| 身份证|姓名|
| - ------|- ------|
| 1个|测验|
fiddle
svmlkihl2#
感谢大家提出的解决方案。我设法解决了我的问题。下面是定义的约束:
据我所知,PostgreSQL会按照创建约束的顺序来检查它们。所以,下面是发生的事情:
1.如果存在
Other Variable -> Current Variable
等参照,则限制删除,否则执行下一步。1.如果有类似
Current Variable -> Other Variable
的引用,请删除级联上variable_variable
表中的Current Variable
及其链接。但是,我遇到了另一个问题,不是约束问题,而是Hibernate问题,
Variable
实体定义如下:我曾经使用简单的Spring Data JPA存储库方法
delete(Variable variable)
删除Variable
,实际上,这是生成的查询:据我所知,拥有方的
ManyToMany
集合总是orphanRemoval = true
,因此Hibernate总是在删除实体本身之前删除ManyToMany
链接(如果我错了请纠正我),因此DB约束毫无意义,因为Hibernate过早地删除了所有链接。现在,我使用原生SQL查询,并标记
delete
和deleteById
方法以抛出UnsupportedOperationException
,这样就不会有人意外调用它们。无论如何,我不认为这是一个清晰的解决方案。您知道如何让Hibernate不要删除所有者端的ManyToMany
链接吗?a5g8bdjr3#
您面临的问题是,删除变量B时,variable_id_to上的外键约束条件variable_variable_id_from_fkey不会被触发,因为它不是使用ON DELETE CASCADE定义的。这意味着variable_variable中引用B的行不会被删除,因此,B的删除将成功进行。
要解决此问题,可以修改variable_id_to上的外键约束条件,使其也具有ON DELETE CASCADE:
通过此修改,当您删除变量B时,variable_variable中引用B的所有行(即,variable_id_to等于B的id)也将被删除。这将防止在任何其他变量引用B时删除B。
要处理变量引用自身的情况,可以向变量表添加一个触发器,该触发器检查变量是否引用自身并删除variable_variable中的相应行:
从变量表中删除行之前将触发此触发器。如果要删除的行的ID出现在variable_variable中某行的两列中,则将删除variable_variable中的相应行。这将允许删除变量,即使该变量引用自身。
通过这些修改、外键约束和触发器,您应该能够满足业务需求并保持数据库结构清晰。
想一想