Re: [sqlalchemy] Relationship behavior change when switching from reflected to declarative styles; test case included

2015-03-04 Thread Evan James
On Tuesday, March 3, 2015 at 4:41:20 PM UTC-5, Michael Bayer wrote:

 Essentially the issue is likely because the mappings in these two examples 
 are not equivalent; the reflection based version has Widget.frobnicator 
 and 
 Frobnicator.widget communicating with each other through a backref, and 
 the 
 declarative version does not. 


Thanks, Michael.  Yes, we're on SQLAlchemy 0.9.  We used a script to 
generate the declarative models by introspecting on the reflective ones, 
and in the process it turned a relationship defined once with a backref 
into two relationships defined without using the backref keyword.  We 
missed that the backref argument is responsible for the event listeners as 
well as for creating the relationship on the other model.

Adding the back_populates argument to the model declarations fixes our 
issue.

Thanks,
Evan James

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.


Re: [sqlalchemy] Relationship behavior change when switching from reflected to declarative styles; test case included

2015-03-03 Thread Michael Bayer


Evan James thas...@gmail.com wrote:

 Hi folks,
 
 I'm working on a SQLAlchemy-based app where we've decided to make some 
 infrastructure changes, in particular moving from reflection to declaration 
 for mapping the models.
 
 However, we're now running into issues where, after switching to declarative, 
 relationships aren't populated the way we expect when manipulated in Python.  
 For example, we have code that looks like this:
 
 class Widget(...):
 def merge(self, other_widget):
 Merge the widgets, transferring the dependent items on the other 
 widget to this one.
 for frobnicator in other_widget.frobnicators[:]:
 frobnicator.widget = self
 
 meta.Session.delete(other_widget)
 
 
 This code worked as hoped-for when we were reflecting on the database to 
 create our mappers, but after switching to declarative, the dependent items 
 are cascade-deleted on commit when other_widget is deleted, rather than being 
 preserved as children of the merged widget.
 
 It's not difficult to fix this particular issue - explicitly removing the 
 frobnicators from the other_widget.frobnicators collection will prevent them 
 from being deleted, and then the merged widget correctly has them - but we're 
 finding we have a class of bugs where relationships aren't being handled the 
 same way as before.  Unfortunately, build a comprehensive test suite is one 
 of the infrastructure changes we're in the process of making - which means 
 it's not done yet and we can't easily track down all the places we could get 
 tripped up.  We would really prefer to resolve this by changing the 
 definitions in the models, not by changing the application code that 
 manipulates the membership of relationships.


Essentially the issue is likely because the mappings in these two examples
are not equivalent; the reflection based version has Widget.frobnicator and
Frobnicator.widget communicating with each other through a backref, and the
declarative version does not.

Assuming you’re on SQLA 0.9, the reflective version is taking advantage of
the behavior introduced in
http://docs.sqlalchemy.org/en/rel_0_9/changelog/migration_09.html#backref-handlers-can-now-propagate-more-than-one-level-deep;
that is, adding frobnicator to first_widget.frobincators affects the backref
of frobnicator.widget which then automatically performs the remove of
second_widget.frobnicators. The declarative version does not make any use of
the “backref” or “back_populates” keyword so cannot take advantage of this
behavior; it doesn’t track any linkage between these two sides.

The section
http://docs.sqlalchemy.org/en/rel_0_9/orm/backref.html?highlight=backref
talks about how to configure either backref or back_populates between
mutually-dependent relationships.



 I've created a reduced test case here which specifically displays the 
 behavior we're having trouble with in minimal form.  If one line in the test 
 case is commented out, the test will pass for reflective models and fail for 
 declarative models; if the line is put back in, success and failure reverse.
 
 My question:  How can we make relationships function identically in 
 declarative syntax as they did in reflective syntax?  We thought we had 
 migrated mapping styles in a way that wouldn't change anything, but here we 
 are.  What are we missing?
 
 Thanks,
 Evan James
 
 -- 
 You received this message because you are subscribed to the Google Groups 
 sqlalchemy group.
 To unsubscribe from this group and stop receiving emails from it, send an 
 email to sqlalchemy+unsubscr...@googlegroups.com.
 To post to this group, send email to sqlalchemy@googlegroups.com.
 Visit this group at http://groups.google.com/group/sqlalchemy.
 For more options, visit https://groups.google.com/d/optout.

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.