2016-04-14 12 views
0

einfacher Code bestehen wie:sqlalchemy: State Management, wie eine unserialize Instanz in der Sitzung

import pickle, cPickle 
from app import session, redis 

class MyObj(DeclarativeBase): 
    @classmethod 
    def get(cls,id): 
     key = cls.__name__+":"+str(id) 
     cached = redis.get(key) 
     if cached: 
      # unserialize to cls instance 
      return cPickle.loads(cached) 
     record = session.query(cls).filter(cls.id==id).one() 
     if record: 
      # serialize and store to redis 
      redis.set(key, pickle.dumps(record)) 
     return record 


# first time , a normal orm instance returned from session query (uncached) 
obj = MyObj.get(1) 

# but the next requests, get cached from redis. 
# and i want to delete the record 
delobj = MyObj.get(1) 
session.delete(delobj) 
session.commit() 

es einen Fehler wie erhöhen "Instanz xxx wird nicht beibehalten"

ich versuchte session.add (DELOBJ) vor dem Löschen ist der Zustand Pending True (state = inspect (delobj)), funktioniert aber immer noch nicht zum Löschen.

Antwort

0

Sie müssen merge im Cache-Instanzen zu aktuellen Sitzung:

merge() transfers state from an outside object into a new or already existing instance within a session.

Von Beispiele:

An application is storing objects in an in-memory cache, shared by many Session objects simultaneously. merge() is used each time an object is retrieved from the cache to create a local copy of it in each Session which requests it. The cached object remains detached; only its state is moved into copies of itself that are local to individual Session objects.

In the caching use case, it’s common to use the load=False flag to remove the overhead of reconciling the object’s state with the database. There’s also a “bulk” version of merge() called merge_result() that was designed to work with cache-extended Query objects - see the section Dogpile Caching .

So:

if cached: 
     # unserialize to cls instance 
     return session.merge(cPickle.loads(cached), load=False) 

auf Cache-Speichern beharrte Objekte von cls nur, oder Sie erhalten den Fehler:

InvalidRequestError: merge() with load=False option does not support objects transient (i.e. unpersisted) objects. flush() all changes on mapped instances before merging with load=False. 

Ein einfacher Weg, um die oben genannten Fehler zu erzeugen:

obj = MyObj() 
cached = pickle.dumps(obj) 
obj2 = session.merge(pickle.loads(cached), load=False) 
... 
InvalidRequestError: merge() with load=False option does not support objects transient (i.e. unpersisted) objects. flush() all changes on mapped instances before merging with load=False. 

Wenn auf der anderen Seite zunächst richtig bestehen das Objekt:

In [63]: obj = MyObj() 

In [64]: session.add(obj) 

In [65]: session.flush() 

In [66]: obj.__dict__ 
Out[66]: 
{'id': 2, 
'_sa_instance_state': <sqlalchemy.orm.state.InstanceState at 0x7fe6f380cac8>} 

In [67]: cached = pickle.dumps(obj) 

In [68]: session.commit() 

In [69]: obj2 = session.merge(pickle.loads(cached), load=False) 

In [70]: obj2 in session 
Out[70]: True 
+0

awesome! Es klappt. aber wenn ich load = False verwendet. es wirft Fehler auf: merge() mit load = False-Option unterstützt Objekte nicht transient (d. h. nicht übergeordnete) Objekte. flush() alle Änderungen an gemappten Instanzen vor dem Zusammenführen mit load = False. – GiveMeFive

+0

Es scheint, dass Sie es irgendwie geschafft haben, Objekte, die nicht persistent in der DB in Ihrem Cache gespeichert wurden, zwischenzuspeichern. Der Fehler wird in [session.py] (https://github.com/zzzeek/sqlalchemy/blob/master/lib/sqlalchemy/orm/session.py#L1761) ausgelöst, wenn kein Primärschlüssel für die zwischengespeicherte Instanz gefunden werden kann ... Ich denke. Von [Statusverwaltung] (http://docs.sqlalchemy.org/en/latest/orm/session_state_management.html): "Transient - Eine Instanz, die sich nicht in einer Sitzung befindet und nicht in der Datenbank gespeichert ist, dh sie hat keine Datenbankidentität. " –

+0

gab es zwei http-Anfrage in meiner App. Aktion einfügen und Aktion löschen ich habe das insert-Ereignis @ event.listens_for (cls, 'after_insert') gehört, automatisch zwischengespeichert, nachdem ein Datensatz eingefügt wurde. und die zweite HTTP-Anfrage, die Instanz aus dem Cache holen (wenn zwischengespeichert wird), um sie zu löschen ... und load = False funktioniert nicht. Vielleicht liegt es daran, dass sie in zwei verschiedenen http-Anfragen arbeiten. – GiveMeFive