> On Nov 24, 2014, at 12:31 PM, Michael Bayer <[email protected]> wrote:
>
>>
>> On Nov 24, 2014, at 1:00 AM, Victor Reichert <[email protected]
>> <mailto:[email protected]>> wrote:
>>
>> I've taken another look at trying to eager load the address.parent. Is it
>> possible to do that?
>
> Unfortuntately not really. It should be in theory but I’m not able to
> work out an eager load that goes to both Customer and Supplier in terms of
> AddressAssociation at the same time. I can get the query to render just fine
> but the eager-targeting logic at the moment doesn’t seem to know how to be
> told to go to two separate subclasses of a base class at the same time.
> There’s probably improvements yet to be made in eager loading to support this
> case better, e.g. this is a bug, but I’ve wrestled with it for about an hour
> and I’m out of time on it for now, sorry. Even if it works, the query is
> very unpleasant to look at :) If I get it working later I’ll send it out.
OK here we go, the limitation is that the of_type() modifier is only recognized
along a particular path once. So to get over this we can use a
with_polymorphic():
poly = with_polymorphic(
AddressAssociation,
[Customer.assoc_cls, Supplier.assoc_cls], aliased=True)
eager_addresses = session.query(Address).options(
joinedload(Address.association.of_type(poly)).joinedload(
poly.CustomerAddressAssociation.parent),
joinedload(Address.association.of_type(poly)).joinedload(
poly.SupplierAddressAssociation.parent),
)
this loads everything in one go. this pattern is documented in terms of
joined inheritance here:
http://docs.sqlalchemy.org/en/rel_0_9/orm/inheritance.html#eager-loading-of-specific-or-polymorphic-subtypes
<http://docs.sqlalchemy.org/en/rel_0_9/orm/inheritance.html#eager-loading-of-specific-or-polymorphic-subtypes>
>
> There’s also a bug in the example, add this, it will help a lot:
>
> diff --git a/examples/generic_associations/discriminator_on_association.py
> b/examples/generic_associations/discriminator_on_association.py
> index e03cfec..7bb04cf 100644
> --- a/examples/generic_associations/discriminator_on_association.py
> +++ b/examples/generic_associations/discriminator_on_association.py
> @@ -84,6 +84,7 @@ class HasAddresses(object):
> "%sAddressAssociation" % name,
> (AddressAssociation, ),
> dict(
> + __tablename__=None,
> __mapper_args__={
> "polymorphic_identity": discriminator
> }
>
>
> this is to override the automated __tablename__ thing in the example.
>
>>
>> I've tried a couple of ways, pasted a below. My full code is at:
>> https://gist.github.com/vfr292/a5939418285e4c8bd03b
>> <https://gist.github.com/vfr292/a5939418285e4c8bd03b>
> the first query should be:
>
> eager_sales_persons = session.query(SalesPerson).options(
> joinedload(SalesPerson.customers).
> joinedload(Customer.addresses.attr[0]).
> joinedload(Customer.addresses.attr[1])
>
> ).all()
>
>
>
>>
>> eager_addresses = session.query(Address).options(joinedload(Address.parent))
>>
>> #error sqlalchemy.exc.ArgumentError: mapper option expects string key or
>> list of attributes
>>
>> eager_addresses =
>> session.query(Address).options(joinedload(Address.association).joinedload(Customer.assoc_cls.parent),
>> joinedload(Address.association).joinedload(Supplier.assoc_cls.parent)).all()
>>
>> #not joining to Customer or Supplier
>>
>> eager_addresses =
>> session.query(Address).outerjoin(Address.association).outerjoin(Customer.assoc_cls.parent).options(contains_eager(Address.parent)).outerjoin(Supplier.assoc_cls.parent).options(contains_eager(Address.parent).all())
>>
>> #error sqlalchemy.exc.ArgumentError: mapper option expects string key or
>> list of attributes
>>
>> Any advice on how I can eager load address.parent would be much appreciated
>> :)
>>
>> Sincere thanks,
>>
>> ~Victor
>>
>> On Sunday, October 26, 2014 3:06:13 AM UTC-7, Michael Bayer wrote:
>>
>>> On Oct 26, 2014, at 12:07 AM, Victor Reichert <[email protected] <>> wrote:
>>>
>>> Hi,
>>>
>>> I am following the "Generic Association with Discriminator on Association"
>>> example at:
>>>
>>> http://docs.sqlalchemy.org/en/latest/_modules/examples/generic_associations/discriminator_on_association.html
>>>
>>> <http://docs.sqlalchemy.org/en/latest/_modules/examples/generic_associations/discriminator_on_association.html>
>>>
>>> However, I would like to eager load the customer.addresses in a query like
>>>
>>> eager_sales_persons =
>>> session.query(SalesPerson).options(joinedload(SalesPerson.customers).joinedload(Customer.addresses))
>>>
>>> #with SalesPerson being a class I added with a relationship to customers.
>>>
>>> However, the above statement raises: 'AssociationProxy' object has no
>>> attribute 'property'
>>>
>>> I tried eager_sales_persons =
>>> session.query(SalesPerson).options(joinedload(SalesPerson.customers).joinedload(Customer.address_association).joinedload(AddressAssociation.addresses)).all()
>>>
>>> however, it would emit SQL for customer.addresses.
>>>
>>> I have made a pastie with my code at: http://pastie.org/9676017
>>> <http://pastie.org/9676017>
>>> Is there a loader strategy that would work for my situation or a work
>>> around for the AssociationProxy error?
>>>
>>>
>>
>> the second query is the right one, as currently there isn’t integration
>> between an association proxy attribute and loader options, meaning, you have
>> to state the joinedload() in terms of the actual relationship() as you are
>> doing.
>>
>> However I’m not seeing the problem:
>>
>> if we load as :
>>
>>
>> session.query(SalesPerson).options(joinedload(SalesPerson.customers).joinedload(Customer.address_association).joinedload(AddressAssociation.addresses)).all()
>>
>> which you can also state like this:
>>
>>
>> session.query(SalesPerson).options(joinedload(SalesPerson.customers).joinedload("address_association").joinedload(“addresses")).all()
>>
>> setting echo=True on create_engine(), the main query is:
>>
>> SELECT salesperson.id <http://salesperson.id/> AS salesperson_id,
>> salesperson.name <http://salesperson.name/> AS salesperson_name,
>> address_association_1.id <http://address_association_1.id/> AS
>> address_association_1_id, address_association_1.discriminator AS
>> address_association_1_discriminator, address_1.id <http://address_1.id/> AS
>> address_1_id, address_1.association_id AS address_1_association_id,
>> address_1.street AS address_1_street, address_1.city AS address_1_city,
>> address_1.zip AS address_1_zip, customer_1.id <http://customer_1.id/> AS
>> customer_1_id, customer_1.name <http://customer_1.name/> AS customer_1_name,
>> customer_1.sales_person_id AS customer_1_sales_person_id,
>> customer_1.address_association_id AS customer_1_address_association_id
>> FROM salesperson LEFT OUTER JOIN customer AS customer_1 ON salesperson.id
>> <http://salesperson.id/> = customer_1.sales_person_id LEFT OUTER JOIN
>> address_association AS address_association_1 ON address_association_1.id
>> <http://address_association_1.id/> = customer_1.address_association_id LEFT
>> OUTER JOIN address AS address_1 ON address_association_1.id
>> <http://address_association_1.id/> = address_1.association_id
>>
>>
>> so in the FROM we have: salesperson -> customer -> address_association ->
>> address
>>
>> that’s correct. you’ll note three joinedload() calls, three links (->).
>>
>> then as the iteration proceeds, the sample calls upon address.parent. This
>> emits this query for two entries:
>>
>> SELECT customer.id <http://customer.id/> AS customer_id, customer.name
>> <http://customer.name/> AS customer_name, customer.sales_person_id AS
>> customer_sales_person_id, customer.address_association_id AS
>> customer_address_association_id
>> FROM customer
>> WHERE ? = customer.address_association_id
>>
>> not sure if that’s the query you’re referring to. That’s Address.parent,
>> which is a proxy to CustomerAddressAssociation.parent, which is emitting a
>> lazy load. As this is the non-FK side of a one-to-one, that’s also
>> correct. A one-to-one is a special case of a one-to-many, basically,
>> uselist=False means, fetch a one-to-many collection, but only deal with the
>> first result. CustomerAddressAssociation.parent is the backref of the
>> Customer.address_association many-to-one that’s stated in the joinedload().
>>
>> if this were a non-generic mapping where Customer.addresses were a
>> one-to-many and Address.parent were a many-to-one, you wouldn’t get that
>> extra load for Address.parent; a pure many-to-one is implicitly retrieved
>> from the database and cached that way when the one-to-many side is loaded.
>> but in this case the “generic” mapping has flipped this around so that
>> Customer->AddressAssoiation is a many-to-one.
>>
>>
>>
>>
>>
>>
>>
>>> Thank you so much for your help :)
>>>
>>> ~Victor
>>>
>>>
>>> --
>>> 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
>>> <http://groups.google.com/group/sqlalchemy>.
>>> For more options, visit https://groups.google.com/d/optout
>>> <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 [email protected]
>> <mailto:[email protected]>.
>> To post to this group, send email to [email protected]
>> <mailto:[email protected]>.
>> Visit this group at http://groups.google.com/group/sqlalchemy
>> <http://groups.google.com/group/sqlalchemy>.
>> For more options, visit https://groups.google.com/d/optout
>> <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 [email protected]
> <mailto:[email protected]>.
> To post to this group, send email to [email protected]
> <mailto:[email protected]>.
> Visit this group at http://groups.google.com/group/sqlalchemy
> <http://groups.google.com/group/sqlalchemy>.
> For more options, visit https://groups.google.com/d/optout
> <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 [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.