[Zope-dev] Re: zope.sqlalchemy

Michael Bayer mike_mp at zzzcomputing.com
Wed May 7 14:04:40 EDT 2008


On May 7, 2008, at 1:29 PM, Laurence Rowe wrote:

> I'm thinking more about having the same classes mapped to different  
> databases at different points in the application. Imagine a  
> departmental address book app. Intstances of the departmental  
> address book are created for each department, each with a different  
> databases:
>
> http://addressbook/sales -> postgres:///sales
> http://addressbook/engineering -> postgres:///engineering
>
> The way I imagine this working is to have a proxy engine object that  
> looks up the real engine through a local utility. Each application  
> would be a `site` and capable of local utility registrations. /sales  
> would have Engine('postgres:///sales') registered and /engineering  
> Engine('postgres:///engineering').
>
> Only a single ScopedSession would be required. This would be bound  
> to proxy that performs the utility lookup. So when in the /sales  
> context the proxy would point to the sales engine and when in the / 
> engineering context to the engineering engine.
>
> The limitation of this approach is that it would not be possible to  
> mix objects from /sales and objects from /engineering into the same  
> transaction. So really we need a session per application instance.  
> Perhaps this can be achieved through a custom scoping function:
>
> def scopefunc():
>    return thread.get_ident(), id(zope.component.getSiteManager())


If you want to mix tables (and optionally engines) for the *same*  
class, we actually have a feature for that too.  Its sort of a feature  
I've wanted to remove but Jason keeps arguing that its worthy.  It's  
called "entity_name" and it allows multiple primary mappers to be  
created for a single class.  The entity_name has to be specified when  
you add the element to the session (yet another reason explicit add()  
is a good thing).  This feature is taken directly from the Hibernate  
feature of the same name.

The limitation with entity_name which needs some more fixing in 0.5 is  
that only one mapper gets to define the attribute instrumentation for  
the entity.  If you are storing the same class in three different  
tables (across three different databases or just one), the attributes  
defined on the class need to be compatible with all three.  This is  
reasonable since a class can only have one descriptor per attribute  
name.   Querying is also slightly challenging since the descriptors  
need to be qualified for a particular mapper (i.e. you cant just say  
query.filter(Address.id==5)...which "id" are we talking about ?)

The reason I'm not totally keen on this feature is that it seems to be  
a very exotic way of getting around making simple subclasses, and I've  
yet to see the use case for it where simple subclasses don't work,  
except for "cosmetic" reasons which I have a hard time swallowing  
(even if the reasons are "cosmetic", you can still create subclasses  
that are all "named" the same).

So I will ask you, why can't your application simply have a  
SalesAddress and an EngineeringAddress class ?   You could even  
produce them transparently using a custom __new__() method, i.e.

class Address(object):
     def __new__(cls, *args, **kwargs):
         if my_scoped_thing.context == 'sales':
             return object.__new__(SalesAddress)
        elif my_scoped_thing.context == 'engineering':
             return object.__new__(EngineeringAddress)

this seems extremely straightforward to me as each object, once  
instantiated is now bound for a specific destination.   It doesnt seem  
like youd want the *same* Address to be stored in one and then the  
other in a different instance (that seems *extremely* complex for no  
good reason).  Isnt explicit better than implicit ?





More information about the Zope-Dev mailing list