2010-05-04 3 views
0

Ici va le pseudo-code des entités de mise à jour/suppression en bloc de type différent en transaction unique. Notez que les entités Album et Song ont AlbumGroup en tant qu'entité racine. (À savoir a la même entité mère)en vrac mise à jour/supprimer des entités de type différent dans db.run_in_transaction

class Album: 
    pass 
class Song: 
    album = db.ReferenceProperty(reference_class=Album,collection_name="songs") 

def bulk_update_album_group(album): 
    updated = [album] 
    deleted = [] 
    for song in album.songs: 
    if song.is_updated: 
     updated.append(song)   
    if song.is_deleted: 
     deleted.append(song) 
    db.put(updated) 
    db.delete(deleted) 

a = Album.all().filter("...").get() 

# bulk update/delete album. 

db.run_in_transaction(bulk_update_album,a) 

Mais j'ai rencontré un célèbre « Seulement Ancêtre requêtes dans les transactions » erreur aux propriétés itérez back-référence comme « album.songs ». Je suppose que le filtre ancestor() n'aide pas car ces entités sont modifiées en mémoire. Donc je modifie l'exemple comme ceci: préparer toutes les entités mises à jour/effacées avant d'appeler la transaction.

def bulk_update_album2(album): 
    updated = [album] 
    deleted = [] 
    for song in album.songs: 
    if song.is_updated: 
     updated.append(song)   
    if song.is_deleted: 
     deleted.append(song) 
    def txn(updated,deleted): 
    db.put(updated) 
    db.delete(deleted) 
    db.run_in_transaction(txn,updated,deleted) 

Maintenant, je trouve que l'arrière-référence itération reload force de la propriété des entités existantes. Donc ré-itérer la propriété de référence arrière après la modification devrait être évitée !!

Tout ce que je veux vérifier est:

Lorsque besoin de mise à jour en vrac/supprimer plusieurs entités de différents types, est-il un bon modèle de codage de cette situation? mon dernier code peut-il être bon?


va ici exemple complet de code:

from google.appengine.ext import webapp 
from google.appengine.ext.webapp import util 

import logging 

from google.appengine.ext import db 

class Album(db.Model): 
    name = db.StringProperty() 
    def __repr__(self): 
     return "%s%s"%(self.name,[song for song in self.songs]) 

class Song(db.Model): 
    album = db.ReferenceProperty(reference_class=Album,collection_name='songs') 
    name = db.StringProperty() 
    playcount = db.IntegerProperty(default=0) 
    def __repr__(self): 
     return "%s(%d)"%(self.name,self.playcount) 

def create_album(name): 
    album = Album(name=name) 
    album.put() 
    for i in range(0,5): 
     song = Song(parent=album, album=album, name='song#%d'%i) 
     song.put() 
    return album 

def play_all_songs(album): 
    logging.info(album) 

    # play all songs 
    for song in album.songs: 
     song.playcount += 1 
     logging.info(song) 

    # play count also 0 here 
    logging.info(album) 

    def save_play_count(album): 
     updated = [] 
     for song in album.songs: 
      updated.append(song) 
     db.put(updated) 

    db.run_in_transaction(save_play_count,album) 

def play_all_songs2(album): 
    logging.info("loading : %s"%album) 

    # play all songs 
    updated = [] 
    for song in album.songs: 
     song.playcount += 1 
     updated.append(song) 

    logging.info("updated: %s"%updated) 
    db.put(updated) 

    logging.info("after save: %s"%album)  

def play_all_songs3(album): 
    logging.info("loading : %s"%album) 

    # play all songs 
    updated = [] 
    for song in album.songs: 
     song.playcount += 1 
     updated.append(song) 

    # reload 
    for song in album.songs: 
     pass 

    logging.info("updated: %s"%updated) 
    def bulk_save_play_count(updated): 
     db.put(updated) 
    db.run_in_transaction(bulk_save_play_count,updated) 

    logging.info("after save: %s"%album) 

class MainHandler(webapp.RequestHandler): 
    def get(self): 
     self.response.out.write('Hello world!') 

     album = Album.all().filter('name =','test').get() 
     if not album:    
      album = db.run_in_transaction(create_album,'test') 

     # BadRequestError: Only ancestor queries are allowed inside transactions. 
     #play_all_songs(album) 

     # ok 
     #play_all_songs2(album) 

     play_all_songs3(album) 

def main(): 
    application = webapp.WSGIApplication([('/', MainHandler)], 
             debug=True) 
    util.run_wsgi_app(application) 


if __name__ == '__main__': 
    main() 

Répondre

1

S'il vous plaît noter Le ReferenceProperty ne suffit pas de mettre les entités dans le même groupe. Lorsque vous créez un modèle Song, vous devez passer un parent argument avec le parent du modèle (par exemple, le Album).

Il ressemble à ceci:

album = Album.all().filter("...").get() 
new_song = Song(name='Seven Nation Army', parent=album) 
new_song.save() 

Voir la documentation about ancestors.

+0

Merci pour votre gentillesse. Mais je passe déjà l'argument parent à l'entité de chanson nouvellement créée. Ce que je veux vérifier est "l'itération de la propriété de référence dans la fonction de transaction est interdite?" –

Questions connexes