パフォーマンス上の理由から、非正規化されたデータベースがあり、一部のテーブルには、他のテーブルの多くの行から集約されたデータが含まれています。SQLAlchemyイベントを使用して、この非正規化されたデータキャッシュを維持したいと思います。例として、私がフォーラムソフトウェアを作成Thread
していて、その情報を効率的に表示するために、スレッド内のすべてのコメントの合計単語数を追跡する列をそれぞれに持たせたいとします。
class Thread(Base):
id = Column(UUID, primary_key=True, default=uuid.uuid4)
title = Column(UnicodeText(), nullable=False)
word_count = Column(Integer, nullable=False, default=0)
class Comment(Base):
id = Column(UUID, primary_key=True, default=uuid.uuid4)
thread_id = Column(UUID, ForeignKey('thread.id', ondelete='CASCADE'), nullable=False)
thread = relationship('Thread', backref='comments')
message = Column(UnicodeText(), nullable=False)
@property
def word_count(self):
return len(self.message.split())
したがって、コメントが挿入されるたびに(簡単にするために、コメントが編集または削除されないようにしましょう)、word_count
関連付けられたオブジェクトの属性を更新する必要がありThread
ます。だから私は次のようなことをしたいです
def after_insert(mapper, connection, target):
thread = target.thread
thread.word_count = sum(c.word_count for c in thread.comments)
print("updated cached word count to", thread.word_count)
event.listen(Comment, "after_insert", after_insert)
したがって、を挿入するComment
と、イベントが発生し、単語数が正しく計算されていることがわかりますが、その変更はThread
データベースの行に保存されません。after_insertのドキュメントには、更新された他のテーブルに関する警告はありませんが、after_deleteなど、他のいくつかのテーブルにはいくつかの警告があります。
では、SQLAlchemyイベントでこれを行うためのサポートされている方法はありますか?私はすでにSQLAlchemyイベントを他の多くの目的で使用しているので、データベーストリガーを作成する代わりに、すべてをそのように実行したいと思います。