Как сделать атомарное увеличение / уменьшение с помощью Elixir / SQLAlchemy - PullRequest
4 голосов
/ 12 ноября 2010

Я хотел бы увеличить (или уменьшить) поле оценки в сущности Elixir:

class Posting(Entity):

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

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

Однако это не работает надежно при одновременных вызовах upvote.Лучшее, что я могу придумать, - это уродливый беспорядок (в основном, построение оператора SQL UPDATE с помощью SQLAlchemy):

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()

Видите ли вы какие-либо проблемы с этим решением?Есть ли более чистые способы достичь того же?

Я бы хотел не использовать здесь блокировки БД.Я использую Elixir, SQLAlchemy, Postgres.

Обновление

Вот вариант, полученный из решения фонПетрушева:

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

Этонесколько лучше, чем мое первое решение, но все же требует фильтрации для текущей сущности.К сожалению, это не работает, если сущность распределена по нескольким таблицам.

1 Ответ

3 голосов
/ 12 ноября 2010

Я попробую, но я не уверен, что это отвечает вашим потребностям:

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

Возможно, вы захотите сделать session.commit () сразу после него?

EDIT : [относительно обновления вопроса]

Если проводка получена из сущности, класс которой сопоставлен с несколькими таблицами, приведенное выше решение остается в силе, но значение атрибута 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 ...>
    })
...