3

既存のデータベースをマップするために SQLAlchemy の設定をテストしています。このデータベースは、使用しなくなった以前のサードパーティ製アプリケーションによってかなり前に自動的にセットアップされたため、外部キー制約などの予期されるものが定義されていません。ソフトウェアは、これらの関係をすべて管理します。

親子関係を持つノード型の生産追跡データベース構造です。nodetype 固有のデータは独自のテーブルに存在し、type、uid、parentUid などの共通列のメインの関係テーブルがあります。

構造はこんな感じ…

  1. 主キー「uid」、「type」列挙、および親ノードを参照する「parentUid」を含む、基本的にすべてのノード エントリを含む階層テーブル。
  2. NodeA / NodeB / ...テーブルには、階層テーブルと1対1で一致する「uid」があります

私が SQLAlchemy のドキュメントから集めたのは、テーブルを「結合」しようとすることです。これが私がこれまでに持っているものです:

# has a column called 'parentUid'
hierarchy = Table('hierarchy', METADATA, autoload=True)

hier_fk = lambda: Column('uid', 
                          Integer, 
                          ForeignKey('hierarchy.uid'), 
                          primary_key=True)

nodeTypeA = Table('nodetype_a', METADATA, nodehier_fk(), autoload=True)
nodeTypeB = Table('nodetype_b', METADATA, nodehier_fk(), autoload=True)

Base = declarative_base()

class NodeA(Base):
    __table__ = join(hierarchy, nodeTypeA)

    id = column_property(hierarchy.c.uid, nodeTypeA.c.uid)
    uid = nodeTypeA.c.uid


class NodeB(Base):
    __table__ = join(hierarchy, nodeTypeB)

    id = column_property(hierarchy.c.uid, nodeTypeB.c.uid)
    uid = nodeTypeB.c.uid

    # cannot figure this one out
    parent = relationship("NodeA", primaryjoin="NodeB.parentUid==NodeA.id")

relationship明らかに間違っており、クラッシュします。foreign_keys私は、属性を定義し、hierarchy.c.uidスタイル アプローチを組み合わせて使用​​する組み合わせを多数試しました。しかし、この他のテーブルとの関係を作る方法がわかりません。

行がなければ、relationshipクエリはうまく機能します。階層テーブルに結合された各ノードの完全な表現を取得します。次のようにして、NodeB の NodeA 親を手動で取得することもできます。

node_a = session.query(NodeA).filter_by(uid=node_b.parentUid).first()

「結合」アプローチは私の目標に適していますか? この関係を機能させるにはどうすればよいですか?

アップデート

これまでのところ、次のように一方向の関係を確立することができました。

children = relationship("NodeB", 
                        primaryjoin="NodeB.parentUid==NodeA.id", 
                        foreign_keys=[hierarchy.c.parentUid],
                        # backref="parent"
            )

しかし、 のコメントを外してbackrefを逆にするとNodeB、次のようになります。

ArgumentError: NodeA.children と後方参照 NodeB.parent は両方とも同じ方向です。多対一側に remote_side を設定するつもりでしたか?

4

1 に答える 1

1

remote_sideは、どちらの側が「リモート」であるかを区別するために自己参照関係で使用されます。フラグについては、http://docs.sqlalchemy.org/en/latest/orm/relationships.html#adjacency-list-relationshipsで説明されています。クラスをjoin()に直接マッピングしているため、SQLAlchemyは各join()をマッピングされたテーブルと見なし、両方の結合が同じベーステーブルに依存しているため、「自己参照」条件が検出されます。結合されたテーブル継承の通常のパターンを使用してこのマッピングを構築する場合(http://docs.sqlalchemy.org/en/latest/orm/inheritance.html#joined-table-inheritanceを参照)、relationship()は次のようになります。明示的なremote_side引数なしで参加する方法を理解するためのもう少しコンテキスト。

与えられたアプローチを使用した完全な例:

from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base

e = create_engine("sqlite://", echo=True)

e.execute("""
create table hierarchy (uid int primary key, parentUid int)
""")

e.execute("""
create table nodetype_a (uid int primary key)
""")

e.execute("""
create table nodetype_b (uid int primary key)
""")

Base = declarative_base()


# has a column called 'parentUid'
hierarchy = Table('hierarchy', Base.metadata, autoload=True, autoload_with=e)

nodehier_fk = lambda: Column('uid',
                          Integer,
                          ForeignKey('hierarchy.uid'),
                          primary_key=True)

nodeTypeA = Table('nodetype_a', Base.metadata, nodehier_fk(), autoload=True, autoload_with=e)
nodeTypeB = Table('nodetype_b', Base.metadata, nodehier_fk(), autoload=True, autoload_with=e)

Base = declarative_base()

class NodeA(Base):
    __table__ = join(hierarchy, nodeTypeA)

    id = column_property(hierarchy.c.uid, nodeTypeA.c.uid)
    uid = nodeTypeA.c.uid


class NodeB(Base):
    __table__ = join(hierarchy, nodeTypeB)

    id = column_property(hierarchy.c.uid, nodeTypeB.c.uid)
    uid = nodeTypeB.c.uid

    # cannot figure this one out
    parent = relationship("NodeA",
                    primaryjoin="NodeB.parentUid==NodeA.id",
                    foreign_keys=hierarchy.c.parentUid,
                    remote_side=hierarchy.c.uid,
                    backref="children")

s = Session(execute)
s.add_all([
        NodeA(children=[NodeB(), NodeB()])
])
s.commit()
于 2012-08-11T20:25:14.390 に答える