- changed status to on hold
Session.merge does work with un-pickled cached instances
I have an application which uses dogpile to cache some SQLALchemy ORM instances. We recently noticed when loading cached objects any instance access still triggers a bunch of SQL queries. This turns out to be caused due to the use of the standard memory backend from dogpile and how that interacts with SQLALchemy's Session.merge: if I try to merge() an instance from another session into the current session SELECTs are triggered, but if do pickle and unpickle the object no SELECTs are run.
import pickle
import sqlalchemy
from sqlalchemy import orm
from sqlalchemy import schema
from sqlalchemy import types
from sqlalchemy.ext.declarative import declarative_base
metadata = schema.MetaData()
BaseObject = declarative_base(metadata=metadata)
class Parent(BaseObject):
__tablename__ = 'parent'
id = schema.Column(types.Integer(), primary_key=True)
name = schema.Column(types.Unicode())
engine = sqlalchemy.create_engine('sqlite:///:memory:', echo=True)
metadata.create_all(engine)
sm = orm.sessionmaker(bind=engine)
Session = orm.scoped_session(sm)
session = Session()
parent = Parent(name='parent')
session.add(parent)
session.flush()
session.commit()
session = Session()
parent = session.query(Parent).first()
pickle_cache = pickle.dumps(parent)
session.commit()
session = Session()
new = session.merge(parent, load=False)
# This triggers a SELECT
print new.name
session.rollback()
session = Session()
new = session.merge(pickle.loads(pickle_cache), load=False)
# This does NOT trigger a SELECT
print new.name
session.rollback()
Comments (6)
-
reporter -
reporter - changed title to Session.merge does work with un-pickled cached instances
- edited description
-
reporter - changed status to open
Updated issue to show what I was really hitting. In my case a workaround is to use the memory_pickle backend from dogpile.cache
-
repo owner I don't see where the bug is. The "triggers a select" example, you are merging a parent that has had all of its attributes marked as expired due to session.commit(). So parent.name has to load. In the "does not trigger a select" example, you are merging a copy of the parent object that was made before the session from which it's original came from was expired. So it has parent.name already populated.
-
repo owner - changed status to on hold
don't see a bug here, though there is a need to copy instances when doing caching.
-
repo owner - changed status to closed
no bug seen here.
- Log in to comment
There is an obvious error in the test-script. I'm trying to track this down further.