4

What if I had something like a double linked list in a relational database, for example:

node_id    left_id    right_id

1          null       2
2          1          3
3          2          null

Then I have some SQLAlchemy code like the following:

class NodeClass(Base):
    __tablename__ = 'nodes_table'
    node_id = Column(Integer, primary_key=True)
    left_id = Column(Integer, ForeignKey('nodes_table.node_id'))
    right_id = Column(Integer, ForeignKey('nodes_table.node_id'))
    left = relationship('NodeClass') # Wrong
    right = relationship('NodeClass') # Wrong

If I have node_id 2, and I call NodeClass.left I would like to receive node_id 1 in return. How can I configure the SQLAlchemy relationships to behave this way?

UPDATE:

I will give a second example. Consider a table of people, and each person has a mother and a father.

person_id    mother_id    father_id

1            null         null
2            null         null
3            1            2

The SQLAlchemy code:

class PersonClass(Base):
    __tablename__ = 'persons_table'
    person_id = Column(Integer, primary_key=True)
    mother_id = Column(Integer, ForeignKey('persons_table.person_id'))
    father_id = Column(Integer, ForeignKey('persons_table.person_id'))
    mother = relation('PersonClass') # Wrong
    father = relation('PersonClass') # Wrong
4

1 回答 1

4

下面的代码展示了如何配置关系:

class NodeClass(Base):
    __tablename__ = 'nodes_table'
    node_id = Column(Integer, primary_key=True)

    left_id = Column(Integer, ForeignKey('nodes_table.node_id'))
    left = relationship('NodeClass', remote_side=[node_id],
            primaryjoin=('NodeClass.left_id==NodeClass.node_id'),
            backref=backref("right", uselist=False),
            #lazy="joined", join_depth=9,
            )

但有几点需要注意:

  • 只存储关系的一端,推断另一端。这可能不是您想要的,但管理起来要简单得多,只设置一侧就足够了,另一侧myNode.left = myOtherNode( right) 将自动设置(因为已配置backref
  • 如果两端都存储(rightleft),那么
    • 两端都需要在代码中设置,并且必须确保它们是一致的,这可能不是一项简单的任务
    • insert-1, insert-2, update-1如果您的主键是在数据库上计算的,则需要插入两个链接的节点,因为在第一个insert.

更新:问题更新部分的示例代码(但仍使用原始类名)。只需指定primaryjoinand uselist=False

class NodeClass(Base):
    __tablename__ = 'nodes_table'
    node_id = Column(Integer, primary_key=True)

    left_id = Column(Integer, ForeignKey('nodes_table.node_id'))
    right_id = Column(Integer, ForeignKey('nodes_table.node_id'))

    left = relationship('NodeClass', primaryjoin = ('NodeClass.left_id == NodeClass.node_id'), use_list=False)
    right = relationship('NodeClass', primaryjoin = ('NodeClass.right_id == NodeClass.node_id'), use_list=False)
于 2012-05-15T12:14:32.593 回答