From b986e0b51762c4f849f7f936e7aaa7d78c61aa70 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Thu, 21 Sep 2006 20:26:33 +0000 Subject: [PATCH] - adjustments to eager loading so that its "eager chain" is kept separate from the normal mapper setup, thereby preventing conflicts with lazy loader operation, fixes [ticket:308] --- CHANGES | 4 ++++ lib/sqlalchemy/orm/mapper.py | 2 +- lib/sqlalchemy/orm/properties.py | 22 +++++++++++++--------- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/CHANGES b/CHANGES index ddba5ec215..decfaafed5 100644 --- a/CHANGES +++ b/CHANGES @@ -26,6 +26,10 @@ updating too many rows, updates only required columns the appropriate negation operator if one is available. - calling a negation on an "IN" or "IS" clause will result in "NOT IN", "IS NOT" (as opposed to NOT (x IN y)). +- adjustments to eager loading so that its "eager chain" is +kept separate from the normal mapper setup, thereby +preventing conflicts with lazy loader operation, fixes +[ticket:308] 0.2.8 - cleanup on connection methods + documentation. custom DBAPI diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index 194b2b9e6f..f8df559022 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -566,7 +566,7 @@ class Mapper(object): prop.adapt_to_inherited(key, mapper) def __str__(self): - return "Mapper|" + self.class_.__name__ + "|" + (self.entity_name is not None and "/%s" % self.entity_name or "") + str(self.local_table) + return "Mapper| " + str(id(self)) + "|" + self.class_.__name__ + "|" + (self.entity_name is not None and "/%s" % self.entity_name or "") + (self.local_table and self.local_table.name or str(self.local_table)) + "|is_primary=" + repr(self._is_primary_mapper()) def _is_primary_mapper(self): """returns True if this mapper is the primary mapper for its class key (class + entity_name)""" diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py index 8372c41f85..23398f8fef 100644 --- a/lib/sqlalchemy/orm/properties.py +++ b/lib/sqlalchemy/orm/properties.py @@ -161,6 +161,8 @@ class PropertyLoader(mapper.MapperProperty): private = property(lambda s:s.cascade.delete_orphan) + def __str__(self): + return self.__class__.__name__ + " " + str(self.parent) + "->" + self.key + "->" + str(self.mapper) def cascade_iterator(self, type, object, recursive): if not type in self.cascade: return @@ -373,6 +375,7 @@ class LazyLoader(PropertyLoader): self._register_attribute(class_, callable_=lambda i: self.setup_loader(i)) def setup_loader(self, instance): + #print self, "setup_loader", "parent", self.parent.mapped_table, "child", self.mapper.mapped_table, "join", self.lazywhere # make sure our parent mapper is the one thats assigned to this instance, else call that one if not self.localparent.is_assigned(instance): # if no mapper association with this instance (i.e. not in a session, not loaded by a mapper), @@ -533,15 +536,15 @@ class EagerLoader(LazyLoader): if len(eagerprops): recursion_stack[self.localparent.mapped_table] = True - self.mapper = self.mapper.copy() + self.eagermapper = self.mapper.copy() try: for prop in eagerprops: if recursion_stack.has_key(prop.target): # recursion - set the relationship as a LazyLoader - p = EagerLazyOption(None, False).create_prop(self.mapper, prop.key) + p = EagerLazyOption(None, False).create_prop(self.eagermapper, prop.key) continue p = prop.copy() - self.mapper.props[prop.key] = p + self.eagermapper.props[prop.key] = p # print "we are:", id(self), self.target.name, (self.secondary and self.secondary.name or "None"), self.parent.mapped_table.name # print "prop is",id(prop), prop.target.name, (prop.secondary and prop.secondary.name or "None"), prop.parent.mapped_table.name p.do_init_subclass(recursion_stack) @@ -552,7 +555,8 @@ class EagerLoader(LazyLoader): #print "new eagertqarget", p.eagertarget.name, (p.secondary and p.secondary.name or "none"), p.parent.mapped_table.name finally: del recursion_stack[self.localparent.mapped_table] - + else: + self.eagermapper = self.mapper self._row_decorator = self._create_decorator_row() self.__eager_chain_init = id(self) @@ -597,7 +601,7 @@ class EagerLoader(LazyLoader): self._aliasize_orderby(statement.order_by_clause, False) statement.append_from(statement._outerjoin) - for key, value in self.mapper.props.iteritems(): + for key, value in self.eagermapper.props.iteritems(): value.setup(key, statement, eagertable=self.eagertarget) @@ -608,7 +612,7 @@ class EagerLoader(LazyLoader): decorated_row = self._decorate_row(row) try: # check for identity key - identity_key = self.mapper._row_identity_key(decorated_row) + identity_key = self.eagermapper._row_identity_key(decorated_row) except KeyError: # else degrade to a lazy loader LazyLoader.execute(self, session, instance, row, identitykey, imap, isnew) @@ -619,11 +623,11 @@ class EagerLoader(LazyLoader): if isnew: # set a scalar object instance directly on the parent object, # bypassing SmartProperty event handlers. - instance.__dict__[self.key] = self.mapper._instance(session, decorated_row, imap, None) + instance.__dict__[self.key] = self.eagermapper._instance(session, decorated_row, imap, None) else: # call _instance on the row, even though the object has been created, # so that we further descend into properties - self.mapper._instance(session, decorated_row, imap, None) + self.eagermapper._instance(session, decorated_row, imap, None) else: if isnew: # call the SmartProperty's initialize() method to create a new, blank list @@ -635,7 +639,7 @@ class EagerLoader(LazyLoader): # store it in the "scratch" area, which is local to this load operation. imap['_scratch'][(instance, self.key)] = appender result_list = imap['_scratch'][(instance, self.key)] - self.mapper._instance(session, decorated_row, imap, result_list) + self.eagermapper._instance(session, decorated_row, imap, result_list) def _create_decorator_row(self): class DecoratorDict(object): -- 2.47.2