我正在尝试在Postgres数据库中建模一些需要“继承”的不同用例,并意识到有多种方法可以做到这一点,我不确定哪种方法最好。
我正在考虑的两个具体用例是:
“会员资格” - 单个“用户”可以是不同类型对象的成员:“团队”,“集合”或“项目”。在这种情况下,成员类型的上限是这三种关系类型。 (现在。)
“事件” - 可以创建与我的数据模型中任何其他对象相关的“事件” - 例如。 “teams.create”,“users.update”,“webhooks.create”,“items.publish”等。在这种情况下,关系的“类型”并没有真正限制,因为每当我添加新的数据模型时,我很有可能想要为它创建事件。
以下是我可以看到实现这些需求的一些方法......
(对这些代码片段使用“Memberships”用例,但同样适用于“Events”用例。)
CREATE TABLE memberships (
id TEXT,
user_id TEXT,
team_id TEXT,
collection_id TEXT,
item_id TEXT,
PRIMARY KEY (id),
FOREIGN KEY (user_id) REFERENCES users (id),
FOREIGN KEY (team_id) REFERENCES teams (id),
FOREIGN KEY (collection_id) REFERENCES collections (id),
FOREIGN KEY (item_id) REFERENCES items (id),
CHECK (
(team_id IS NOT NULL)::integer +
(collection_id IS NOT NULL)::integer +
(item_id IS NOT NULL)::integer = 1
)
);
优点:
JOIN
s不那么冗长。缺点:
NULL
列值。CHECK
约束有点奇怪吗?*_id
列并更改CHECK
。CREATE TABLE memberships (
id TEXT,
user_id TEXT,
target_type TEXT,
target_id TEXT,
PRIMARY KEY (id),
FOREIGN KEY (user_id) REFERENCES users (id),
CHECK (target_type IN ('team', 'collection', 'items'))
);
优点:
NULL
列值。缺点:
JOIN
个查询有点冗长。CHECK
约束。CREATE TABLE team_memberships (
id TEXT,
user_id TEXT,
team_id TEXT,
PRIMARY KEY (id),
FOREIGN KEY (user_id) REFERENCES users (id),
FOREIGN KEY (team_id) REFERENCES teams (id)
);
CREATE TABLE collection_memberships (
id TEXT,
user_id TEXT,
collection_id TEXT,
PRIMARY KEY (id),
FOREIGN KEY (user_id) REFERENCES users (id),
FOREIGN KEY (collection_id) REFERENCES collections (id)
);
CREATE TABLE item_memberships (
id TEXT,
user_id TEXT,
item_id TEXT,
PRIMARY KEY (id),
FOREIGN KEY (user_id) REFERENCES users (id),
FOREIGN KEY (item_id) REFERENCES items (id)
);
优点:
NULL
列值。缺点:
一对列方法似乎很普遍,但这意味着数据库不再自动为您处理外键关系,这似乎是一个非常大的缺点 - 如{{1}不再是一种选择。对我而言,这似乎是一个负面因素,使其成为一个合法的选择。
许多表方法似乎也很普遍,对于“成员资格”用例,这是有道理的。但对于其他用例,例如“事件”(可以创建与数据库中的任何对象相关的事件,而不是预约束列表),那么拥有如此大量的表似乎不实用。
XOR Columns 方法看起来并不普遍,或者至少我找不到关于它的信息,但感觉就像一个很好的平衡,仍然让数据库做了所有这项工作没有增加很多表格。
XOR列方法是否存在明显问题?
有推荐的解决方法吗?