self.add_property(key, value)
def add_property(self, key, prop):
- """adds an indiviual MapperProperty to this mapper. If the mapper has not been compiled yet,
- just adds the property to the initial properties dictionary sent to the constructor. if this Mapper
+ """add an indiviual MapperProperty to this mapper.
+
+ If the mapper has not been compiled yet, just adds the property to the initial
+ properties dictionary sent to the constructor. if this Mapper
has already been compiled, then the given MapperProperty is compiled immediately."""
self.properties[key] = prop
if self.__is_compiled:
else:
return None
- def _compile_property(self, key, prop, init=True, skipmissing=False):
- """adds an additional property to this mapper. this is the same as if it were
- specified within the 'properties' argument to the constructor. if the named
- property already exists, this will replace it. Useful for
- circular relationships, or overriding the parameters of auto-generated properties
- such as backreferences."""
-
+ def _compile_property(self, key, prop, init=True, skipmissing=False, localparent=None):
+ """add a MapperProperty to this or another Mapper, including configuration of the property.
+
+ The properties' parent attribute will be set, and the property will also be
+ copied amongst the mappers which inherit from this one.
+
+ if the given prop is a Column or list of Columns, a ColumnProperty will be created.
+ """
self.__log("_compile_property(%s, %s)" % (key, prop.__class__.__name__))
if not isinstance(prop, MapperProperty):
if prop is None:
raise exceptions.ArgumentError("'%s' is not an instance of MapperProperty or Column" % repr(prop))
- self.__props[key] = prop
+ effectiveparent = localparent or self
+ effectiveparent.__props[key] = prop
prop.set_parent(self)
-
+
if isinstance(prop, ColumnProperty):
col = self.select_table.corresponding_column(prop.columns[0], keys_ok=True, raiseerr=False)
if col is None:
proplist.append(prop)
if init:
- prop.init(key, self)
+ prop.init(key, effectiveparent)
- for mapper in self._inheriting_mappers:
+ for mapper in effectiveparent._inheriting_mappers:
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 "") + (self.local_table and self.local_table.name or str(self.local_table)) + (not self._is_primary_mapper() and "|non-primary" or "")
identitykey = self._row_identity_key(row)
if session.has_key(identitykey):
instance = session._get(identitykey)
+ self.__log_debug("_instance(): using existing instance %s identity %s" % (mapperutil.instance_str(instance), str(identitykey)))
isnew = False
if version_check and self.version_id_col is not None and self._getattrbycolumn(instance, self.version_id_col) != row[self.version_id_col]:
raise exceptions.ConcurrentModificationError("Instance '%s' version of %s does not match %s" % (instance, self._getattrbycolumn(instance, self.version_id_col), row[self.version_id_col]))
instance = self.extension.create_instance(self, session, row, imap, self.class_)
if instance is EXT_PASS:
instance = self._create_instance(session)
- self.__log_debug("new instance %s identity %s" % (mapperutil.instance_str(instance), str(identitykey)))
+ self.__log_debug("_instance(): created new instance %s identity %s" % (mapperutil.instance_str(instance), str(identitykey)))
imap[identitykey] = instance
isnew = True
else:
class LazyLoader(PropertyLoader):
def do_init_subclass(self):
+ print "LAZYLOADER %d DOINITSUBCLASS" % id(self)
(self.lazywhere, self.lazybinds, self.lazyreverse) = create_lazy_clause(self.parent.unjoined_table, self.primaryjoin, self.secondaryjoin, self.foreignkey)
# determine if our "lazywhere" clause is the same as the mapper's
# get() clause. then we can just use mapper.get()
lazywhere.accept_visitor(li)
if secondaryjoin is not None:
lazywhere = sql.and_(lazywhere, secondaryjoin)
+ LazyLoader.logger.debug("create_lazy_clause " + str(lazywhere))
return (lazywhere, binds, reverse)
oldprop = mapper.props[key]
newprop = class_.__new__(class_)
newprop.__dict__.update(oldprop.__dict__)
- newprop.do_init_subclass()
- mapper._compile_property(key, newprop)
+ #newprop.do_init_subclass()
+ p = newprop
+ while p.inherits is not None:
+ p = p.inherits
+ real_parent_mapper = p.parent
+ real_parent_mapper._compile_property(key, newprop, localparent=mapper)
class DeferredOption(GenericOption):
def __init__(self, key, defer=False, **kwargs):
sess.clear()
au = sess.query(usermapper).get_by(user_name='jack')
self.assert_(au.email_address == 'jack@gmail.com')
+
+ def testlazyoption(self):
+ """test that a lazy options gets created against its correct mapper when
+ using options with inheriting mappers"""
+ class _Order(object):
+ pass
+ class _User(object):
+ pass
+ class AddressUser(_User):
+ pass
+ ordermapper = mapper(_Order, orders)
+ usermapper = mapper(_User, users,
+ properties = {
+ 'orders' : relation(ordermapper, lazy=True)
+ })
+ amapper = mapper(AddressUser, addresses, inherits = usermapper)
+
+ sess = create_session()
+
+ def go():
+ l = sess.query(AddressUser).options(lazyload('orders')).select()
+ # this would fail because the "orders" lazyloader gets created against AddressUsers selectable
+ # and not _User's.
+ assert len(l[0].orders) == 3
+ self.assert_sql_count(db, go, 2)
+
class DeferredTest(MapperSuperTest):