[sqlalchemy] Re: Aw: [sqlalchemy] Re: 0.4: can not append objects to instrumentedlists
[EMAIL PROTECTED] wrote: I spent some time to migrate to sqlalchemy 0.4 and it's to late to go back to 0.3. What can I do to add objects to properties (InstumentedLists) in sqlalchemy 0.4 (with different mappers)? I suspect that case will work if you add the user to the session under the desired entity_name before appending to the collection. --~--~-~--~~~---~--~~ 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 -~--~~~~--~~--~--~---
[sqlalchemy] Re: Aw: [sqlalchemy] Re: 0.4: can not append objects to instrumentedlists
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=gstq=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
[sqlalchemy] Aw: [sqlalchemy] Re: Aw: [sqlalchemy] Re: 0.4: can not append objects to instrumentedlists
many thanks to jason and michael! I add the objects to the current session and ... it works. Migration to 0.5 seems to be a big step (for us). We don't use fancy orm tricks. The only thing are 'user dependet table spaces'. Hence its possible your example, michael, can work for us. Thanks. greetings, tyr - Original Nachricht Von: Michael Bayer [EMAIL PROTECTED] An: sqlalchemy@googlegroups.com Datum: 13.10.2008 19:51 Betreff: [sqlalchemy] Re: Aw: [sqlalchemy] Re: 0.4: can not append objects to instrumentedlists 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-dy namicmodels.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