On 9/2/15 10:22 PM, Dave Vitek wrote:
On 9/2/2015 10:08 PM, Mike Bayer wrote:


On 9/2/15 9:57 PM, Dave Vitek wrote:
Answering my own question.

Here's a patch that seems to fix it, but I am uncertain about whether it breaks other things. Use at your own risk, at least until someone more familiar with this code evaluates it.


this is a variant of a known issue, that of object X is being loaded in different contexts in the same row, with different loader strategies applied. The first context that hits it wins.

I'm adding your test case to that issue at https://bitbucket.org/zzzeek/sqlalchemy/issues/3431/object-eager-loaded-on-scalar-relationship.

the patch which is there seems to fix this test as well - it is extremely similar to your patch, so nice job!


I have a question about your patch. If "existing" is None and is not present in dict_, it does not get placed into dict_. I note that load_scalar_from_joined_new_row puts it into dict_ regardless of whether it is None. Is this intentional/good?

it was intentional, as far as "good", that's part of why i didn't merge this in too quickly; I usually have to spend a few hours deeply re-familiarizing with sections like these before making assumptions. the new/existing row thing has to do with the fact that the join returns for us the parent object multiple times. the first time we see the parent, it's "new". the subsequent times, it's "existing". So here we are looking at a related item. If we call _instance() and get None back, that means the columns for the related item were incomplete, e.g. primary key is incomplete / missing. There shouldn't be a case where the row is None for "new" and non-None for "existing", but this is based on my not having re-familiarized with this section yet.








Index: lib/sqlalchemy/orm/strategies.py
===================================================================
--- lib/sqlalchemy/orm/strategies.py    (revision 114304)
+++ lib/sqlalchemy/orm/strategies.py    (working copy)
@@ -1474,20 +1474,24 @@
     def _create_scalar_loader(self, context, key, _instance):
         def load_scalar_from_joined_new_row(state, dict_, row):
             # set a scalar object instance directly on the parent
             # object, bypassing InstrumentedAttribute event handlers.
             dict_[key] = _instance(row, None)

         def load_scalar_from_joined_existing_row(state, dict_, row):
             # call _instance on the row, even though the object has
             # been created, so that we further descend into properties
             existing = _instance(row, None)
+            if key in dict_:
+                assert dict_[key] is existing
+            else:
+                dict_[key] = existing
             if existing is not None \
                 and key in dict_ \
                     and existing is not dict_[key]:
                 util.warn(
                     "Multiple rows returned with "
                     "uselist=False for eagerly-loaded attribute '%s' "
                     % self)

         def load_scalar_from_joined_exec(state, dict_, row):
             _instance(row, None)

- Dave

On 9/2/2015 7:29 PM, Dave Vitek wrote:
Hi all,

I've come across what I'm pretty sure is a bug with contains_eager when there are multiple joinpaths leading to the same row, and only some of those joinpaths are using contains_eager all they way down the joinpath.

I've prepared a test case:
http://pastebin.com/CbyUMdqC

See the text at the top of the test case for further details.

- Dave





--
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 [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to