SQLAlchemy联合约束检查

5

我使用类似以下方式在SQLAlchemy中创建了一个多对多关系:

b_c = Table('b_c', 
            Column('b_id', UUIDType(binary=False), ForeignKey('b.id'), primary_key=True),
            Column('c_id', UUIDType(binary=False), ForeignKey('c.id'), primary_key=True)
           )

这里的 c 和 b 是只有一个id列(UUIDType(binary=false))的表,其模型类似于以下内容:

class A(object):
    __tablename__ = 'a'
    id = Column('id', UUIDType(binary=False), default=uuid.uuid4, primary_key=True)

class B(object):
    __tablename__ = 'b'
    id = Column('id', UUIDType(binary=False), default=uuid.uuid4, primary_key=True)
    a_id = Column(UUIDType(binary=False), ForeignKey('a.id'), nullable=False)
    a = relationship('A')

class C(object):
    __tablename__ = 'c'
    id = Column('id', UUIDType(binary=False), default=uuid.uuid4, primary_key=True)
    a_id = Column(UUIDType(binary=False), ForeignKey('a.id'), nullable=False)
    a = relationship('A')

这种关系完全正常,我可以将B和C对象过滤到父级A中以适应我的使用场景。然而,为了确保数据的完整性超出使用这些模型的逻辑之外,是否有任何最佳实践要求对于任何关系b_cb.a必须等于c.a?如果在表本身的值上设置简单的CHECK约束条件,那么任何示例都不需要加入已连接表的值。

为什么AC要继承自object而不是Model - Haleemur Ali
谢谢您指出这一点,在试图删除一些不必要的细节时错过了它 - 已更新问题。 - Miek
1个回答

8

根据文档:

目前,CHECK表达式不能包含子查询,也不能引用当前行以外的变量。可以引用系统列tableoid,但不能引用其他任何系统列。

你所描述的无法通过check约束来完成,但可以通过sql触发器在插入或更新之前实现:

以下是一个postgresql函数和触发器定义,用于检查所引用表的a_id外键是否相等。

CREATE FUNCTION ckref_b_c() RETURNS trigger AS $ckref_b_c$
  DECLARE
  bid uuid;
  cid uuid;
  BEGIN
    select a_id INTO bid FROM b WHERE id = NEW.b_id;
    select a_id INTO cid FROM c WHERE id = NEW.c_id;
    IF bid != cid THEN 
        RAISE EXCEPTION 'associated records do not refer to same parent in `a`';
    END IF;
    RETURN NEW;
  END;
 $ckref_b_c$ LANGUAGE plpgsql;

CREATE TRIGGER ckref_b_c BEFORE INSERT OR UPDATE ON b_c
  FOR EACH ROW EXECUTE PROCEDURE ckref_b_c(); 
您可以在创建表格后通过sqlalchemy引擎执行这些查询。 Sqlalchemy还具有事件系统,您可以使用它自动发出这些查询。

我认为你已经解决了这个问题。今天我进一步研究时,尝试使用子查询执行CHECK操作时,感觉自己走上了一条非常丑陋的路。正如你在回答中提到的,这在Postgres中是不允许的:https://dev59.com/E2kw5IYBdhLWcg3wDWIk这绝对是一个合适的解决方案,因为我几乎没有找到任何人推荐使用“hack”函数来创建约束。我通常会避免使用触发器,但在这种情况下似乎很合适。感谢你的帮助! - Miek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接