级联删除未预期工作的孩子

发布于 2025-01-30 15:45:04 字数 2442 浏览 3 评论 0原文

我有两个表是针对不同公司的多态性关系,并且我添加了对ID的外键参考,以确保如果我删除父母,则所有孩子都将被删除。使用此表设置下面的设置,如果我删除父公司,孩子公司坚持不懈,这不是我所期望的。如果我通过父级及其子女级联删除corporation_realationship删除公司,如果我通过child_id删除关系,则父母和兄弟姐妹不受影响。我的问题是我做错了什么,如何通过删除父母而在不添加任何新专栏的情况下删除孩子?

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

CREATE TYPE "corporation_relationship_type" AS ENUM (
  'campus',
  'network'
);

CREATE TABLE "corporations" (
  "id" uuid PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(),
  "name" varchar(255) NOT NULL
);

CREATE TABLE "corporation_relationships" (
  "parent_id" uuid NOT NULL,
  "child_id" uuid NOT NULL,
  "type" corporation_relationship_type NOT NULL,
  PRIMARY KEY ("parent_id", "child_id")
);

ALTER TABLE "corporation_relationships" ADD FOREIGN KEY ("parent_id") REFERENCES "corporations" ("id") ON DELETE CASCADE;

ALTER TABLE "corporation_relationships" ADD FOREIGN KEY ("child_id") REFERENCES "corporations" ("id") ON DELETE CASCADE;

示例查询:

如果我添加了2家公司,然后将关系添加到类似的两个公司:

insert into corporations (id, name) values ('f9f8f7f6-f5f4f3f2-f1f0f0f0-f0f0f0f0', 'Father');


insert into corporations (id, name) values ('f9f8f7f6-f5f4f3f2-f1f0f0f0-f0f0f0f1', 'Son');

insert into corporation_relationships (parent_id, child_id) values ('f9f8f7f6-f5f4f3f2-f1f0f0f0-f0f0f0f0', 'f9f8f7f6-f5f4f3f2-f1f0f0f0-f0f0f0f1');

我的select *从公司中选择 *的输出;将是:

                  id                  |        name
--------------------------------------+--------------------
 f9f8f7f6-f5f4-f3f2-f1f0-f0f0f0f0f0f0 | Father
 f9f8f7f6-f5f4-f3f2-f1f0-f0f0f0f0f0f1 | Son
(2 rows)

我的select * select * from corporation_relationships; IS:

              parent_id               |               child_id               |  type
--------------------------------------+--------------------------------------+--------
 f9f8f7f6-f5f4-f3f2-f1f0-f0f0f0f0f0f0 | f9f8f7f6-f5f4-f3f2-f1f0-f0f0f0f0f0f1 | campus

现在,如果我通过执行从id ='f9f8f7f6-f5f4-f4-f3f2-f1-f0-f0-f0-f0-f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0'; 删除“父”;,我希望我的输出我的输出从公司; 什么都不是,但相反,它是以下内容:

                  id                  |        name
--------------------------------------+--------------------
 f9f8f7f6-f5f4-f3f2-f1f0-f0f0f0f0f0f1 | Son
(1 row)

还值得注意的是,Corporation_Relationships表格在此删除后也为空,但是我希望Cascade继续越过该表格并删除儿童实体并删除该表格也是如此。

I have two tables one of which is for the polymorphic relationship of different corporations and I've added foreign key references to ids to ensure that if I delete a parent all children will be deleted. With this table setup below if I delete a parent corporation the child corporation persists which is not what I expected. If I delete a corporation_relationship via the parent_id the parent and its children cascade delete and if I a delete the relationship via the child_id the parent and siblings are unaffected. My questions are what am I doing wrong and how can I ensure that by deleting a parent the children are also deleted without adding any new columns?

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

CREATE TYPE "corporation_relationship_type" AS ENUM (
  'campus',
  'network'
);

CREATE TABLE "corporations" (
  "id" uuid PRIMARY KEY NOT NULL DEFAULT uuid_generate_v4(),
  "name" varchar(255) NOT NULL
);

CREATE TABLE "corporation_relationships" (
  "parent_id" uuid NOT NULL,
  "child_id" uuid NOT NULL,
  "type" corporation_relationship_type NOT NULL,
  PRIMARY KEY ("parent_id", "child_id")
);

ALTER TABLE "corporation_relationships" ADD FOREIGN KEY ("parent_id") REFERENCES "corporations" ("id") ON DELETE CASCADE;

ALTER TABLE "corporation_relationships" ADD FOREIGN KEY ("child_id") REFERENCES "corporations" ("id") ON DELETE CASCADE;

Example queries:

If I add 2 corporations and then add a relationship to the two like so:

insert into corporations (id, name) values ('f9f8f7f6-f5f4f3f2-f1f0f0f0-f0f0f0f0', 'Father');


insert into corporations (id, name) values ('f9f8f7f6-f5f4f3f2-f1f0f0f0-f0f0f0f1', 'Son');

insert into corporation_relationships (parent_id, child_id) values ('f9f8f7f6-f5f4f3f2-f1f0f0f0-f0f0f0f0', 'f9f8f7f6-f5f4f3f2-f1f0f0f0-f0f0f0f1');

My output for select * from corporations; will be:

                  id                  |        name
--------------------------------------+--------------------
 f9f8f7f6-f5f4-f3f2-f1f0-f0f0f0f0f0f0 | Father
 f9f8f7f6-f5f4-f3f2-f1f0-f0f0f0f0f0f1 | Son
(2 rows)

My output for select * from corporation_relationships; is:

              parent_id               |               child_id               |  type
--------------------------------------+--------------------------------------+--------
 f9f8f7f6-f5f4-f3f2-f1f0-f0f0f0f0f0f0 | f9f8f7f6-f5f4-f3f2-f1f0-f0f0f0f0f0f1 | campus

Now if I delete the 'father' by executing delete FROM corporations WHERE id = 'f9f8f7f6-f5f4-f3f2-f1f0-f0f0f0f0f0f0'; I would expect my output of select * from corporations; to be nothing but instead it is the following:

                  id                  |        name
--------------------------------------+--------------------
 f9f8f7f6-f5f4-f3f2-f1f0-f0f0f0f0f0f1 | Son
(1 row)

Also, it is noteworthy that the corporation_relationships table is empty after this delete as well but I would want the cascade to keep going past that table and delete the child entity as well.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

吃不饱 2025-02-06 15:45:04

您在corporation_realationships表中的第二个外键约束,引用corporations表不带您对corporiations 表。 >。要澄清,此外键在Corporations表中删除引用的行时,请级联删除。但是你需要相反的。

为了使其正如您在设计中所期望的所期望的那样,您应该拥有 corporations中的一列,该专栏引用了corporation_relationships < /strong>。

因此,您需要

  1. 创建一个主键列,例如 id corporation_relationships (不是您已经拥有的那些,这不是PK,它是独特的约束)。
  2. Corporations中创建列 添加外键对其参考创建corporation_ryationships pk
  3. Corporation_Relationationships 中删除child_id列,此时它是不正确且无用的。
  4. 当您创建一个关系时,应该将其设置为 id fk列 conder> comporiations 中的相应 Child Row
    现在,如果您删除a parent Corporation ,它将删除所有关系,这些
    将递归删除Corporation 的子女。

同时,我认为您的设计不正确。

要定义类似树的关系,您不需要过境表,即
Corporation_Realationships。您可以在单个公司表中定义它。为此,您只需要一个列 parent_id ,这些将是带有级联删除规则的外键,在此表中引用a pk 。顶级父母公司将在 parent_id 中具有 null ,所有孩子 - 父母的 id value。

另外, type corporation_realationships不是关系本身的属性,而是儿童的属性。

Your second foreign key constraint in the corporation_relationships table, that references to the corporations table has nothing with with your expectations of cascade deletions of children rows in corporations. To clearify, this foreign key do cascade deletions when you delete a referenced row in the corporations table. But you need the opposite.

To make it work as you expect in your design, you should have a column in corporations that references a primary key in corporation_relationships.

So you need to

  1. create a primary key column, e.g. id, in corporation_relationships (not those you already have, it's not a pk, it's a unique constraint).
  2. create a column in corporations and add a foreign key constraint on it that references a created corporation_relationships pk.
  3. Remove a child_id column from corporation_relationships, it's incorrect and useless at this point.
  4. When you create a relation you should set it's id to the fk column of corresponding child row in corporations.
    Now, if you delete a parent corporation, it would delete all relationships, those will delete corresponding children of corporation and so on recursively.

Meanwhile, in my opinion, your design is not correct.

To define a tree-like relations you do not need the transit table, i.e
corporation_relationships. You can define it in a single corporations table. For that you need just a one column parent_id, those would be a foreign key with cascade delete rule, that references a pk in this table. Top-parent corporations would have a null in parent_id, all children - parent's id value.

Also, type column in corporation_relationships is not an attribute of relation itself, it's an attribute of child.

我的黑色迷你裙 2025-02-06 15:45:04

Postgres与可选的多态关系没有晶体的参考完整性,因此我为我创建了一个触发因素:



CREATE FUNCTION cascade_delete_children() RETURNS trigger AS $
    BEGIN
        -- Check if the corporation is a parent
        IF OLD.id IN (SELECT parent_id FROM corporation_relationships) THEN
            -- Delete all of the corporation's children
            DELETE FROM corporations WHERE id IN (SELECT child_id FROM corporation_relationships WHERE parent_id = OLD.id);
        END IF;
        RETURN OLD;
    END;
$ LANGUAGE plpgsql;

CREATE trigger cascade_delete_children BEFORE DELETE ON corporations
    FOR EACH ROW EXECUTE PROCEDURE cascade_delete_children();

Postgres doesn't mantain referential integrity with optional polymorphic relationships so I created a trigger to do this for me:



CREATE FUNCTION cascade_delete_children() RETURNS trigger AS $
    BEGIN
        -- Check if the corporation is a parent
        IF OLD.id IN (SELECT parent_id FROM corporation_relationships) THEN
            -- Delete all of the corporation's children
            DELETE FROM corporations WHERE id IN (SELECT child_id FROM corporation_relationships WHERE parent_id = OLD.id);
        END IF;
        RETURN OLD;
    END;
$ LANGUAGE plpgsql;

CREATE trigger cascade_delete_children BEFORE DELETE ON corporations
    FOR EACH ROW EXECUTE PROCEDURE cascade_delete_children();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文