2017-04-26 1 views
0

2つの外部キーを持つsqlalchemyエンティティは、2つの全く異なる親のうちの1つを持つことができるためです。説明のためにアドレス,お客様およびサプライヤを使用してみましょう。 住所顧客またはサプライヤに属することができます(私の場合は子供を持つことができます)。sqlalchemyでの一般的な関連付け(複数の親)によるカスケードdelete-orphan

私はすぐにそれがゼロの両親、すなわちカスタマーもはそれを参照サプライヤーもないとして、削除autoにアドレスとその子供が欲しいです。 Iが最初SQLAlchemyのドキュメントによれば

class Address(Base): 
    __tablename__ = 'addresses' 
    id = Column(Integer, primary_key=True) 
    customer_id = Column(Integer, ForeignKey('customers.id') 
    supplier_id = Column(Integer, ForeignKey('suppliers.id') 
    # etc ... 

としてこれを実現

Generic Associationsを実装する正規の方法は、テーブルごと関連またはテーブル当たり関連のいずれかを使用することによるものです。これらの両方は、しかし、削除カスケードの問題に対処していないようです:

  • テーブルあたりの関連:住所は、独自の子供を持っているので、私は、関連ごとにアドレス以下の階層全体を複製する必要があります。後方参照が住所にインストールされていると、これが私の最初の実装と同じになるようですが、今すぐに両親が協会内の行です除い:そうでなければ、問題はちょうどテーブルごとの会合
  • アドレスの子どもたちへ移動します表。 delete-orphanがここでどのように機能するかわかりません。

delete-orphanのカスケードをsqlalchemyの汎用アソシエーションで処理する正しい方法は何ですか?

答えて

0

答えを見つけました。この問題に多対多リレーションシップ(本質的にどのテーブルが関連しているか)があったので、SOのrelatedquestionsがあります。 SQLAlchemy Wikiには、問題の解決方法が記載されています。

ソリューションは、基本的には、各フラッシュの後にクリーンアップイベントリスナー実装することにより、手動でdelete-orphanを行うことです:最初の代わりに、単に私の場合、私は孤児を読み込むこと

@event.listens_for(Session, 'after_flush') 
def delete_address_orphans(session, ctx): 
    if any(isinstance(i, Address) for i in session.dirty): 
     query = session.query(Address).\ 
       filter_by(customer=None, supplier=None) 
     orphans = query.all() 
     for orphan in orphans: 
      session.delete(orphan) 

注意を、クエリに.delete()を追加しますステートメント。これは、後者がAddressエンティティのカスケードをバイパスし、Addressの子を削除しないためです。

関連する問題