0

次の問題に頭を悩ませようとしています:

AABおよびの3 つのクラスがありますB

class AB(Base):
    id = Column(Integer, primary_key=True)
    a_id = Column(Integer, ForeignKey('a.id'), nullable=False)
    a = relationship(
        'A', 
        cascade='save-update', 
        backref=backref(
            'abs', 
            cascade='save-update', 
            uselist=True
        )
    )
    b_id = Column(Integer, ForeignKey('b.id'), nullable=False)
    b = relationship(
        'B', 
        cascade='save-update', 
        backref=backref(
            'abs', 
            cascade='save-update', 
            uselist=True
        )
    )
    __tablename__ = 'ab'

class A(Base)
    id = Column(Integer, primary_key=True)
    __tablename__ = 'a'

class B(Base)
    id = Column(Integer, primary_key=True)
    __tablename__ = 'b'

A基本的に、これはとの間の m2m 関係Bです。唯一の非標準的なことはid、テーブルに列があることですAB。それには理由があります。

の 2 つのインスタンスの「マージ」を実装したいと考えていますA。と が与えられa1ますa2。次に、 を削除する前に、 とのa1すべての関係をABに再割り当てする必要がありますa2。プロセスでの値を保持することは非常に重要ですAB.id(したがって、 の新しいインスタンスをAB実際に作成または削除するべきではありません)。

問題 どのようにしようとしても、 のインスタンスを削除するたびにA、SQLAlchemy はforeign_key を値で更新しようとするためNULL結果としてNOT NULL制約が破られます。それは明示的に発行することによってそれを行いUPDATE ab SET a_id = NULL WHERE id = ...ます。プログラムに次のループがありますが、そうします。

for ab in a1.abs:
    ab.a_id = a2.id
    session.db.add(ab)

session.db.delete(a1)

abしたがって、削除が発行される前に、に関連するすべての sa1が安全に に移動されたように思えますがa2、何かが間違っています。

いくつかの非解決策

  • passive_deletes旗。動作の違いは、メモリにまだ存在しない行のみに関係するため、適切ではありません。
  • deleteカスケードを追加することは、私にとって非常に危険です。abマージの過程でオブジェクトが失われないようにしたいのです。
  • アソシエーションに保持されているリストを手動で更新しても、何の効果もないようです (TheUPDATEが再度発行されます)。

助けていただければ幸いです。

4

2 に答える 2

0

うーん...ここで何かが非常に間違っています。

「UPDATE ab SET a_id = NULL WHERE id = a1.id」は、ab.a_id = a1.id であるすべての ab を既に更新しているため、0 行に影響するはずです。

したがって、考えられる説明は 1 つだけです。ab の更新に失敗しました。コンピュータは嘘をつかない傾向があります。私たちは時々彼らの論理を見逃すだけです。

私の解決策:すべてが問題ないことを確認するには、削除を発行する前に、 a1.id を指す ab のすべての行を見つけます。予想通り、少なくとも 1 つ見つかった場合は、その行がまだそこにある理由を理解しようとします。

おそらく、session.db.add(ab) は session.db.update(ab) のようなものに置き換えることができ、add() は ab テーブルに新しい行を追加しています。または、更新が存在しないか使用できない場合は、次に、コピーを正しく作成したことを確認した後、ab.a_id = a1.id のすべての ab を最初に削除します (作成したと思います)。

于 2013-08-27T15:54:34.367 に答える