4

Elixir エンティティのスコア フィールドをインクリメント (またはデクリメント) したい:

class Posting(Entity):

  score = Field(Integer, PassiveDefault(text('0')))

  def upvote(self):
      self.score = self.score + 1

ただし、これは upvote への同時呼び出しでは確実に機能しません。私が思いつくことができる最高のものは、この醜い混乱です(基本的に、SQLAlchemyでSQL UPDATEステートメントを構築します):

def upvote(self):
    # sqlalchemy atomic increment; is there a cleaner way?
    update = self.table.update().where(self.table.c.id==self.id)
    update = update.values({Posting.score: Posting.score + 1})
    update.execute()

このソリューションに問題はありますか? 同じことを達成するためのよりクリーンな方法はありますか?

ここで DB ロックを使用することは避けたいと思います。Elixir、SQLAlchemy、Postgres を使用しています。

アップデート

以下は、vonPetrushev のソリューションから派生したバリアントです。

def upvote(self):
    Posting.query.filter_by(id=self.id).update(
        {Posting.score: Posting.score + 1}
    )

これは私の最初のソリューションよりもいくらか優れていますが、現在のエンティティをフィルタリングする必要があります。残念ながら、エンティティが複数のテーブルに分散している場合、これは機能しません。

4

1 に答える 1

2

試してみますが、これがあなたのニーズを満たすかどうかはわかりません:

session.query(Posting).\
    .filter(Posting.id==self.id)\
    .update({'score':self.score+1})

その直後に session.commit() を実行したいですか?

編集:[質問の更新について]

Posting が複数のテーブルにマップされたクラスである Entity から派生した場合、上記の解決策は引き続き有効ですが、Posting.id 属性の意味が変更されます。つまり、一部のテーブルの列にマップされなくなり、別の構成にマップされます。 . ここ: http://docs.sqlalchemy.org/en/latest/orm/nonstandard_mappings.html#mapping-a-class-against-multiple-tables を定義する方法を確認できます。次のようになることをお勧めします。

    j = join(entity_table_1, entity_table_2)
    mapper(Entity, j, properties={
        'id': column_property(entity_table_1.c.id, entity_table_2.c.user_id)
        <... some other properties ...>
    })
于 2010-11-12T19:02:41.533 に答える