- marked as critical
- changed milestone to 0.8.0final
merge_result() may throw an exception with joined query results sets
from sqlalchemy/orm/loading.py in 0.8 or sqlalchemy/orm/query.py in 0.7
A query like:
session.query(Table_a, Table_b).outerjoin(Table_a.relation_table_b)
can produce result sets like:
[Table_a instance1>, None), (<Class Table_a instance2>, None), (<Class Table_a instance2>, <Class Table_b instance1>)]((<Class)
The 'None' types cause an exception in merge_result() when it tries to evaluate {{{attributes.instance_state(newrowi)}}} and newrowi is None
Line 129-136 of loading.py:
for row in iterator:
newrow = list(row)
for i in mapped_entities:
newrow[i](i) = session._merge(
attributes.instance_state(newrow[i](i)),
attributes.instance_dict(newrow[i](i)),
load=load, _recursive={})
result.append(util.KeyedTuple(newrow, keys))
To fix this, I added a check:
for row in iterator:
newrow = list(row)
for i in mapped_entities:
if newrow[i](i) is not None:
newrow[i](i) = session._merge(
attributes.instance_state(newrow[i](i)),
attributes.instance_dict(newrow[i](i)),
load=load, _recursive={})
result.append(util.KeyedTuple(newrow, keys))
In any case, it seems like a design accident that merge_result() works at all with tuples of class instances instead of a single class instance or list of rows; so, it may require a little more work to generalize merge_results() without any unintended consequences
Comments (5)
-
repo owner -
repo owner backport to 0.7
-
Account Deleted Replying to zzzeek:
In any case, it seems like a design accident that merge_result() works at all with tuples of class instances instead of a single class instance or list of rows; so, it may require a little more work to generalize merge_results() without any unintended consequences
I'm not following this part. Do you mean,
query.merge_result((some_object, some_other_object))
as opposed toquery.merge_result([some_other_object)]((some_object,))
? the "iterator" argument tomerge_result()
is always supposed to be a list of entities or list of rows, which are linked to the structure of thatQuery
. Basically whatever comes out ofQuery.__iter__()
, for thatQuery
is what it supports.Got it- I'll stop attributing your really great design to some random accident... Thanks for the quick response.
-
repo owner - changed status to resolved
-
repo owner - removed milestone
Removing milestone: 0.8.0final (automated comment)
- Log in to comment
Replying to psharfstein:
got that, OK
I'm not following this part. Do you mean,
query.merge_result((some_object, some_other_object))
as opposed toquery.merge_result([some_other_object)]((some_object,))
? the "iterator" argument tomerge_result()
is always supposed to be a list of entities or list of rows, which are linked to the structure of thatQuery
. Basically whatever comes out ofQuery.__iter__()
, for thatQuery
is what it supports.