[sqlalchemy] Re: Aw: [sqlalchemy] Re: 0.4: can not append objects to instrumentedlists

2008-10-13 Thread jason kirtland

[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

2008-10-13 Thread Michael Bayer


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

2008-10-13 Thread _tyr_

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