Hi all,
As is probably obvious from some of my previous posts, I'm trying to
use a polymorphic mapper (via a MapperExtension). As is probably
also obvious, there seem to be a few problems. Anyway, I think I've
got to the bottom of one of them; in Michael's example
"polymorph2.py", the MapperExtension looks like this:
# MapperExtension object.
class PersonLoader(MapperExtension):
def create_instance(self, mapper, row, imap, class_):
if row[person_join.c.type] =='engineer':
return Engineer()
elif row[person_join.c.type] =='manager':
return Manager()
else:
return Person()
def populate_instance(self, mapper, session, instance, row,
identitykey, imap, isnew):
if row[person_join.c.type] =='engineer':
Engineer.mapper.populate_instance(session, instance,
row, identitykey, imap, isnew, frommapper=mapper)
return False
elif row[person_join.c.type] =='manager':
Manager.mapper.populate_instance(session, instance,
row, identitykey, imap, isnew, frommapper=mapper)
return False
else:
return sqlalchemy.mapping.EXT_PASS
which is fine *except* that if you look carefully, you'll spot that
you can easily end up with more than one instance of e.g. Engineer or
Manager for the same person_id, because the _instance() method in
mapper.py initially generates the identity_key (which is the key
SQLAlchemy uses to ensure that object instances are unique) from the
Person mapper, not from the Engineer or Manager mappers. As a
result, it won't find a pre-existing Engineer or Manager object, and
all sorts of crazy behaviour can then ensue.
There are a few possible approaches to fixing this:
1. Add another method to the MapperExtension class to find the mapper
to use for identity key generation. This has the advantage that it's
straightforward, and it also maintains the existing MapperExtension-
based approach. However, the disadvantage is that the
MapperExtension code required for polymorphism is getting less and
less obvious.
2. Add a method to MapperExtension specifically to support
polymorphism, and push the (effects of) the code above down into
Mapper. This has the advantage that the implementation of
polymorphism won't require mapping the row data into the required
form for the target class's mapper twice (like it does at the
moment), and it also would simplify using a MapperExtension for this
purpose. But perhaps this is too specialised a change to a generic
extension mechanism?
3. Add polymorphism support directly to the Mapper class itself. So
instead of writing
mapper(Person, person_join, extension=personLoaderExtension)
you might write
mapper(Person, person_join, type_selector=person_join.c.type,
type_map={ 'engineer': Engineer, 'manager': Manager })
This would be easier to understand IMO, and doesn't preclude use of a
MapperExtension for any other purpose.
I want to use this functionality, so I'm happy to do the work and
submit a patch; I'm just trying to work out what everyone prefers
syntax/design-wise.
Kind regards,
Alastair.
--
http://www.alastairs-place.net
-------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
Sqlalchemy-users mailing list
Sqlalchemy-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/sqlalchemy-users