On Sep 5, 2010, at 1:27 PM, Freewind wrote:

> There are two classes: User and Question
> 
> A user may have many questions, and it also contains a question_count
> to record the the count of questions belong to him.
> 
> So, when I add a new question, I want update the question_count of the
> user. At first, I do as:
> 
>    question = Question(title='aaa', content='bbb')
>    Session.add(question)
>    Session.flush()
> 
>    user = question.user
>    ### user is not None
>    user.question_count += 1
>    Session.commit()
> 
> Everything goes well.
> 
> But I wan't to use event callback to do the same thing. As following:
> 
>    from sqlalchemy.orm.interfaces import MapperExtension
>    class Callback(MapperExtension):
>        def after_insert(self, mapper, connection, instance):
>             user = instance.user
>             ### user is None !!!
>             user.question_count += 1

Not really sure why question.user would be None here if you had set it (in your 
example above, its not set, unless you have some odd join condition going on), 
but it would also be more appropriate here for the extension to be on the User 
class, not Question, using before_insert().  


> 
> 2. If I change that line to:
> 
>    Session.query(User).filter_by(id=instance.user_id).one()
> 
>   I can get the user successfully, But: the user can't be updated!
> 
>   Look I have modified the user:
> 
>       user.question_count += 1
> 
>   But there is no 'update' sql printed in the console, and the
> 'question_count' are not updated.

So, if you were to emit the INSERT statements for both your User and your 
Question, assuming Question has a foreign key to User, which would INSERT would 
need to occur first ?   The "User" row would already have been inserted here by 
the time your Question after_insert is invoked (and the fact that you can look 
it up proves it).   People usually use before_insert() which states in its doc 
that you can't manipulate the flush plan or assume it will change in any way at 
that point, but I guess I'll make this message much more explicit for all the 
intra-flush() hooks.


> 
> 3. I try to add 'Session.flush()' or 'Session.commit()' in the
> 'after_insert()' method, but both cause errors.

The error should be clear here - "Session is already flushing".    The 
extension points are within a transaction, within a flush.    Invoking flush() 
within flush() is not something that is possible, and invoking commit() within 
flush(), assuming the reentrant flush() issue weren't present, would mean half 
of the flush is committed, half not, and the transaction would then be 
incorrectly committed before it was actually committed on the outside.


-- 
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.

Reply via email to