> On Nov 24, 2014, at 12:31 PM, Michael Bayer <mike...@zzzcomputing.com> wrote: > >> >> On Nov 24, 2014, at 1:00 AM, Victor Reichert <vfr...@gmail.com >> <mailto:vfr...@gmail.com>> 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 <vfr...@gmail.com <>> 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 sqlalchemy+...@googlegroups.com <>. >>> To post to this group, send email to sqlal...@googlegroups.com <>. >>> 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 sqlalchemy+unsubscr...@googlegroups.com >> <mailto:sqlalchemy+unsubscr...@googlegroups.com>. >> To post to this group, send email to sqlalchemy@googlegroups.com >> <mailto:sqlalchemy@googlegroups.com>. >> 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 sqlalchemy+unsubscr...@googlegroups.com > <mailto:sqlalchemy+unsubscr...@googlegroups.com>. > To post to this group, send email to sqlalchemy@googlegroups.com > <mailto:sqlalchemy@googlegroups.com>. > 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 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.