2010-11-12 4 views
4

Je voudrais incrémenter (ou décrémenter) un champ de score dans une entité Elixir:Comment faire incrément/décrément atomique avec Elixir/SQLAlchemy

class Posting(Entity): 

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

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

Cependant, cela ne fonctionne pas de manière fiable avec des appels simultanés upvote. Le mieux que je pouvais venir avec ce gâchis est laid (construction essentiellement une instruction SQL UPDATE avec 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() 

Voyez-vous des problèmes avec cette solution? Existe-t-il des moyens plus propres d'atteindre la même chose? Je voudrais éviter d'utiliser des verrous DB ici. J'utilise Elixir, SQLAlchemy, Postgres.

Mise à jour

est ici une variante qui est dérivé de la solution de vonPetrushev:

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

C'est un peu plus agréable que ma première solution, mais nécessite encore filtrer l'entité actuelle. Malheureusement, cela ne fonctionne pas si l'entité est répartie sur plusieurs tables.

Répondre

3

Je vais essayer, mais je ne sais pas si cela répond à vos besoins:

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

Vous pourriez vouloir faire session.commit() juste après?

EDIT: [concernant la mise à jour de question]

Si l'affichage est dérivé de l'entité qui classe mappée à plusieurs tables, la solution ci-dessus est toujours debout, mais le sens de l'attribut Posting.id est modifié, c'est-à-dire qu'il n'est plus mappé à la colonne d'une table, mais à une composition différente. Ici: http://docs.sqlalchemy.org/en/latest/orm/nonstandard_mappings.html#mapping-a-class-against-multiple-tables vous pouvez voir comment le définir. Je suggère qu'il sera comme:

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 ...> 
    }) 
+2

Ce n'est pas une opération atomique, le score pourrait avoir été mis à jour avant l'exécution de la requête. –

Questions connexes