gue*_*tli 5 postgresql database-design constraints foreign-keys
我们的产品有一个核心模块和几个可选插件.
核心是一个名为的数据库表ticket_type.
可选插件通过1:1关系扩展ticket_type表.这个表叫做myplugin_ticket_type_extension.
对于每行中myplugin_ticket_type_extension都有一行ticket_type.这通过ForeignKey强制执行.到目前为止问题:-)
现在困难的部分:如何强制myplugin_ticket_type_extension每一行都有一行ticket_type?
困难的部分:myplugin是一个可选的插件.该产品的核心不应该知道这个插件的任何信息.
强制执行此操作的最简单方法是添加第二个外键来ticket_type引用扩展表。
这种循环依赖的困难在于,INSERT在您有机会创建另一个记录之前,进入任一表都会违反外键约束。您可以通过使用延迟约束来避免这种情况,这将延迟外键检查,直到事务提交:
CREATE TABLE ticket_type (id INT PRIMARY KEY);
CREATE TABLE myplugin_ticket_type_extension (
id INT PRIMARY KEY,
ticket_type_id INT UNIQUE NOT NULL FOREIGN KEY
REFERENCES ticket_type (id)
DEFERRABLE INITIALLY DEFERRED
);
ALTER TABLE ticket_type ADD FOREIGN KEY (id)
REFERENCES myplugin_ticket_type_extension (ticket_type_id)
DEFERRABLE INITIALLY DEFERRED;
BEGIN;
INSERT INTO ticket_type VALUES (1);
INSERT INTO myplugin_ticket_type_extension VALUES (1,1);
COMMIT;
Run Code Online (Sandbox Code Playgroud)
另一种可能值得考虑的方法是使用表继承:
CREATE TABLE ticket_type (id INT PRIMARY KEY);
CREATE TABLE myplugin_ticket_type_extension (extension_field INT) INHERITS (ticket_type);
INSERT INTO myplugin_ticket_type_extension (id, extension_field) VALUES (1,1);
Run Code Online (Sandbox Code Playgroud)
查询时会显示插入扩展表的记录ticket_type,因此您的核心模块应该不受影响。您可以ticket_type通过添加触发器来阻止直接插入到表中,触发器可以完全阻止插入(通过引发异常),也可以自动将新记录重定向到扩展表:
CREATE FUNCTION ticket_type_trg() RETURNS TRIGGER AS $$
BEGIN
INSERT INTO myplugin_ticket_type_extension (id) VALUES (new.id);
RETURN NULL;
END
$$
LANGUAGE plpgsql;
CREATE TRIGGER ticket_type_trg
BEFORE INSERT ON ticket_type FOR EACH ROW
EXECUTE PROCEDURE ticket_type_trg();
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
69 次 |
| 最近记录: |