On Oct 13, 2008, at 12:22 PM, [EMAIL PROTECTED] wrote:
> >> What is preventing you from simply mapping different classes ? > Different Customers uses different (her own) table spaces. So we > must map a Class to different tables. > > You remove entity_name, but how you specify the 'user dependent > storage' in sqlalchem 0.5? This behavior is a typical orm-property. > I know its a "enterprise requirement". But it is the reason why I > use sqlalchemy. It's specifically a Hibernate/Java ORM requirement, because in Java, subclasses are not cheap. The reality is, by using "entity_name", you associate an "entity_name" attribute with your instance after it's added to the Session, which then determines behavior of that instance. Before its added, there is no "entity_name", and behavior is undefined. In Hibernate, the ORM defines much less behavior on classes since you are required to spell out all instance members and collections explicitly. Hibernate also does not place any behavior upon non-instantiated classes; most Python ORMs like SQLAlchemy do, i.e. you can say "Customer.name=='ed'". 0.5 relies much more heavily on class behavior in terms of querying than previous versions. As you can see here: http://www.hibernate.org/hib_docs/v3/reference/en/html/persistent-classes-dynamicmodels.html , Hibernate uses entity_name to add "dynamic" class behavior to Java, something the language otherwise does not have. Python is already a dynamic language so there's many ways to solve the problem that entity_name does in Hibernate. Because of the way SQLA adds behavior to instances, through instrumentation, the only way "entity_name" can ever work in a solid, "enterprise" sense of the word is if it is specified upon instance creation, i.e. MyInstance(foo, bar, entity_name='foo'). Class behavior is also not possible at all and special "wrappers" are needed to achieve SQLA's class level behavior, i.e. SomeClass = myentity(MyClass, 'foo'); SomeClass.name == 'ed' (additionally, any number of classes can be sent to session.query() now, so theres no place for an "entity_name" keyword argument in any case). There is really no "abstraction" of entity from mapped instance here - they need to be stated together. With that restriction in mind, you can get similar behavior without an entity_name feature at all: class Customer(object): def __new__(cls, entity_name, *args, **kw): if entity_name == 'ed': return object.__new__(EdCustomer) elif entity_name == 'wendy': return object.__new__(WendyCustomer) else: raise Exception("unknown entity %s" % entity_name) querying looks like: sess.query(WendyCustomer).filter(WendyCustomer.some_number==12) an equivent function to mapper() with entity_name which creates types dynamically (and also stores them in a dict): mappers = {} def entity_mapper(basecls, table, entity_name, **kwargs): cls = type.__new__(type, "%s%s" % (entity_name, basecls.__name__), (basecls,), {}) m = mapper(cls, table, **kwargs) mappers[(basecls, entity_name)] = m return cls If you've built entity_mapper, we can rewrite Customer to use the mappers as a guide: def entity_named(cls, entity_name): try: return mappers[(cls, entity_name)].class_ except KeyError: raise Exception("unknown entity %s" % entity_name) class Customer(object): def __new__(cls, entity_name, *args, **kw): return object.__new__(entity_named(cls, entity_name)) So the equivalent of: c = Customer() sess.save(c, entity_name='foo') becomes: c = Customer(entity_name='foo') sess.save(c) the equivalent of: sess.query(Customer, entity_name="foo").filter(customer_table.c.name=='ed').... becomes: EdCustomer = entity_named(Customer, "foo") sess.query(EdCustomer).filter(EdCustomer.name=='ed')... Theres many ways to roll behavior like the above, these are just some ideas. The main idea is that entity_name isn't adding any value that you can't create more effectively on your own. For more background, I wrote about this here: http://groups.google.com/group/sqlalchemy/browse_thread/thread/9e23a0641a88b96d/391326fcf89c05d4?lnk=gst&q=entity_name#391326fcf89c05d4 . As far as the specfic issue you're having, it does seem like an 0.4 bug - its consulting the lazy loader for the instance when none should be consulted at all, if the object is only transient. So Jek's suggestion of placing the object in the session before accessing the collection is a good bet for 0.4. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~----------~----~----~----~------~----~------~--~---