[sqlalchemy] MapperExtension.[before|after]_update problem

2010-10-13 Thread Christophe de Vienne
Hi all,

I am running into an issue with MapperExtension.[before|after]_update.

Context
---

SQLAlchemy 0.5.8
TurboGears 1.1.1

Description
---

I will attempt a simple description first, as I don't think my actual
code will help (I know it is not a thing to say, but really).

We have 2 mapped classes, Parent and Child.

Child is mapped this way :

mapper(Child, child_table, properties={
  parent=relation(Parent, backref='children')
})

And parent has a mapperextension that defines a after_update :

def after_update(self, mapper, connection, instance):
for child in instance.children:
child.name = 'another name'


If I do 2 session flush() after modifying a Parent instance, the
modifications on the children should be reflected to the database.

It is the case in my unit tests if I use directly the DBSession and
manipulate the objects 'myself'.

BUT, if I go through the complete TG stack, in the unittests or in
real-life, the modifications done on child are never sent to the database.

One subtle thing though : if, before the first flush(), I access the
children attribute, the problem goes away.

Example :

parent = DBSession.query(Parent).get('myid')
parent.name = 'test'
# parent.children # Un-commenting this line solve the issue, but of
  # course it is not an acceptable solution
DBSession.flush()
DBSession.flush()

I could not reproduce in a simpler context, and don't know how to go
further in my investigation.

Help ?

Thanks

Christophe

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalch...@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] MapperExtension.[before|after]_update problem

2010-10-13 Thread Conor

 On 10/13/2010 10:55 AM, Christophe de Vienne wrote:

Hi all,

I am running into an issue with MapperExtension.[before|after]_update.

Context
---

SQLAlchemy 0.5.8
TurboGears 1.1.1

Description
---

I will attempt a simple description first, as I don't think my actual
code will help (I know it is not a thing to say, but really).

We have 2 mapped classes, Parent and Child.

Child is mapped this way :

mapper(Child, child_table, properties={
   parent=relation(Parent, backref='children')
})

And parent has a mapperextension that defines a after_update :

def after_update(self, mapper, connection, instance):
 for child in instance.children:
 child.name = 'another name'


If I do 2 session flush() after modifying a Parent instance, the
modifications on the children should be reflected to the database.

It is the case in my unit tests if I use directly the DBSession and
manipulate the objects 'myself'.

BUT, if I go through the complete TG stack, in the unittests or in
real-life, the modifications done on child are never sent to the database.

One subtle thing though : if, before the first flush(), I access the
children attribute, the problem goes away.

Example :

parent = DBSession.query(Parent).get('myid')
parent.name = 'test'
# parent.children # Un-commenting this line solve the issue, but of
   # course it is not an acceptable solution
DBSession.flush()
DBSession.flush()

I could not reproduce in a simpler context, and don't know how to go
further in my investigation.

Help ?

Thanks

Christophe


AFAIK SQLAlchemy does not support the following in MapperExtensions:

   * lazy-loading related objects (maybe?)
   * changing the flush plan, which I believe means changing which
 objects are considered new, dirty, or deleted

Your code is possibly trying to do both. You need to instead create a 
SessionExtension and override before_flush, which allows you to modify 
the session however you want, e.g. (untested):


class MySessionExtension(object):
def before_flush(self, session, flush_context, instances):
for obj in session.dirty:
if isinstance(obj, Parent):
for child in obj.children:
child.name = 'another name'

-Conor

--
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalch...@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.