From: Mike Bayer Date: Sun, 18 Jun 2006 00:56:25 +0000 (+0000) Subject: lazy load and deferred load operations require the parent object X-Git-Tag: rel_0_2_4~31 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=69549460f79975c71007accfd219e9e18f6f09c2;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git lazy load and deferred load operations require the parent object to be in a Session to do the operation; whereas before the operation would just return a blank list or None, it now raises an exception. Session.update() is slightly more lenient if the session to which the given object was formerly attached to was garbage collected; otherwise still requires you explicitly remove the instance from the previous Session. --- diff --git a/CHANGES b/CHANGES index 93727226a1..c847502277 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,13 @@ 0.2.4 - try/except when the mapper sets init.__name__ on a mapped class, supports python 2.3 +- lazy load and deferred load operations require the parent object +to be in a Session to do the operation; whereas before the operation +would just return a blank list or None, it now raises an exception. +- Session.update() is slightly more lenient if the session to which +the given object was formerly attached to was garbage collected; +otherwise still requires you explicitly remove the instance from +the previous Session. 0.2.3 - overhaul to mapper compilation to be deferred. this allows mappers diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py index 843bcf8173..e56350cecb 100644 --- a/lib/sqlalchemy/orm/properties.py +++ b/lib/sqlalchemy/orm/properties.py @@ -68,20 +68,22 @@ class DeferredColumnProperty(ColumnProperty): if not self.localparent.is_assigned(instance): return mapper.object_mapper(instance).props[self.key].setup_loader(instance) def lazyload(): - session = sessionlib.object_session(instance) - if session is None: - return None - clause = sql.and_() - connection = session.connection(self.parent) try: pk = self.parent.pks_by_table[self.columns[0].table] except KeyError: pk = self.columns[0].table.primary_key + + clause = sql.and_() for primary_key in pk: attr = self.parent._getattrbycolumn(instance, primary_key) if not attr: return None clause.clauses.append(primary_key == attr) + + session = sessionlib.object_session(instance) + if session is None: + raise exceptions.InvalidRequestError("Parent instance %s is not bound to a Session; deferred load operation of attribute '%s' cannot proceed" % (instance.__class__, self.key)) + connection = session.connection(self.parent) try: if self.group is not None: @@ -348,18 +350,19 @@ class LazyLoader(PropertyLoader): def lazyload(): params = {} allparams = True - session = sessionlib.object_session(instance) #print "setting up loader, lazywhere", str(self.lazywhere), "binds", self.lazybinds - if session is not None: - for col, bind in self.lazybinds.iteritems(): - params[bind.key] = self.parent._getattrbycolumn(instance, col) - if params[bind.key] is None: - allparams = False - break - else: - allparams = False + for col, bind in self.lazybinds.iteritems(): + params[bind.key] = self.parent._getattrbycolumn(instance, col) + if params[bind.key] is None: + allparams = False + break + if not allparams: return None + + session = sessionlib.object_session(instance) + if session is None: + raise exceptions.InvalidRequestError("Parent instance %s is not bound to a Session; lazy load operation of attribute '%s' cannot proceed" % (instance.__class__, self.key)) # if we have a simple straight-primary key load, use mapper.get() # to possibly save a DB round trip diff --git a/lib/sqlalchemy/orm/session.py b/lib/sqlalchemy/orm/session.py index 7c86fafb50..7508348241 100644 --- a/lib/sqlalchemy/orm/session.py +++ b/lib/sqlalchemy/orm/session.py @@ -363,21 +363,21 @@ class Session(object): self.uow.register_deleted(obj) def _attach(self, obj): - """given an object, attaches it to this session. """ + """Attach the given object to this Session.""" if getattr(obj, '_sa_session_id', None) != self.hash_key: old = getattr(obj, '_sa_session_id', None) - if old is not None: + if old is not None and _sessions.has_key(old): raise exceptions.InvalidRequestError("Object '%s' is already attached to session '%s' (this is '%s')" % (repr(obj), old, id(self))) # auto-removal from the old session is disabled. but if we decide to # turn it back on, do it as below: gingerly since _sessions is a WeakValueDict # and it might be affected by other threads - try: - sess = _sessions[old] - except KeyError: - sess = None - if sess is not None: - sess.expunge(old) + #try: + # sess = _sessions[old] + #except KeyError: + # sess = None + #if sess is not None: + # sess.expunge(old) key = getattr(obj, '_instance_key', None) if key is not None: self.identity_map[key] = obj