2012-05-14 58 views
4

如果我有這樣的事情在關係數據庫中的雙鏈表,例如:使用SQLAlchemy的多個自參照外鍵

node_id left_id right_id 

1   null  2 
2   1   3 
3   2   null 

然後,我有一些SQLAlchemy的代碼如下所示:

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 

如果我有node_id 2,並且我打電話NodeClass.left我想接收node_id 1作爲回報。我如何配置SQLAlchemy關係來表現這種方式?

更新:

我會舉第二個例子。考慮一張人的桌子,每個人都有一位母親和一位父親。

person_id mother_id father_id 

1   null   null 
2   null   null 
3   1   2 

的SQLAlchemy的代碼:

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

下面的代碼演示瞭如何配置的關係:

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期間是未知的。

UPDATE:示例代碼的問題的更新部分(但仍使用原來的類名)。人們只需要指定primaryjoinuselist=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) 
+0

雙鏈表的例子是我能想出的最簡單的例子。實際上,我有更復雜的數據,而且我無法更改數據庫模式。我所關心的主要問題是多個自引用外鍵,但是您已將它們從問題中刪除,因此您的解決方案不能直接適用。不過,它給了我一個很好的起點。 – Buttons840

+0

@ Buttons840:您的第二個示例現在很容易回答:對於每個關係(父/月,或左/右),您需要通過* primaryjoin *子句指定連接條件。我將很快添加到答案中。 – van

+0

我在主連接時遇到問題。由於equals(==)上的兩個操作數都是NodeClass,它如何知道哪個NodeClass是當前節點,以及哪個NodeClass是相關節點?當我要求「離開」時,它可以被解釋爲「給我另一個節點,其ID等於我的left_id」或「給我另一個節點,其left_id等於我的ID」。相反。我試過這個,它不起作用。我想我需要使用別名表,但我不知道如何在聲明式類中執行此操作。 – Buttons840