------------------------------------------------------------------
In order to make the :meth:`.Query.yield_per` method easier to use,
-an exception is raised if any joined or subquery eager loaders are
+an exception is raised if any subquery eager loaders, or joined
+eager loaders that would use collections, are
to take effect when yield_per is used, as these are currently not compatible
with yield-per (subquery loading could be in theory, however).
-When this error is raised, the :meth:`.Query.enable_eagerloads` method
-should be called with a value of False to disable these eager loaders.
+When this error is raised, the :func:`.lazyload` option can be sent with
+an asterisk::
+
+ q = sess.query(Object).options(lazyload('*')).yield_per(100)
+
+or use :meth:`.Query.enable_eagerloads`::
+
+ q = sess.query(Object).enable_eagerloads(False).yield_per(100)
+
+The :func:`.lazyload` option has the advantage that additional many-to-one
+joined loader options can still be used::
+
+ q = sess.query(Object).options(
+ lazyload('*'), joinedload("some_manytoone")).yield_per(100)
+
.. _migration_migration_deprecated_orm_events:
raise sa_exc.InvalidRequestError(
"The yield_per Query option is currently not "
"compatible with %s eager loading. Please "
- "specify query.enable_eagerloads(False) in order to "
+ "specify lazyload('*') or query.enable_eagerloads(False) in "
+ "order to "
"proceed with query.yield_per()." % message)
@_generative()
rows (which are most).
The :meth:`.Query.yield_per` method **is not compatible with most
- eager loading schemes, including joinedload and subqueryload**.
- For this reason it typically should be combined with the use of
- the :meth:`.Query.enable_eagerloads` method, passing a value of
- False. See the warning below.
+ eager loading schemes, including subqueryload and joinedload with
+ collections**. For this reason, it may be helpful to disable
+ eager loads, either unconditionally with
+ :meth:`.Query.enable_eagerloads`::
+
+ q = sess.query(Object).yield_per(100).enable_eagerloads(False)
+
+ Or more selectively using :func:`.lazyload`; such as with
+ an asterisk to specify the default loader scheme::
+
+ q = sess.query(Object).yield_per(100).\\
+ options(lazyload('*'), joinedload(Object.some_related))
.. warning::
from sqlalchemy.orm import (
attributes, mapper, relationship, create_session, synonym, Session,
aliased, column_property, joinedload_all, joinedload, Query, Bundle,
- subqueryload)
+ subqueryload, backref, lazyload)
from sqlalchemy.testing.assertsql import CompiledSQL
from sqlalchemy.testing.schema import Table, Column
import sqlalchemy as sa
self.assert_compile(query, expected, dialect=default.DefaultDialect())
-class YieldTest(QueryTest):
+class YieldTest(_fixtures.FixtureTest):
+ run_setup_mappers = 'each'
+ run_inserts = 'each'
+
+ def _eagerload_mappings(self, addresses_lazy=True, user_lazy=True):
+ User, Address = self.classes("User", "Address")
+ users, addresses = self.tables("users", "addresses")
+ mapper(User, users, properties={
+ "addresses": relationship(
+ Address, lazy=addresses_lazy,
+ backref=backref("user", lazy=user_lazy)
+ )
+ })
+ mapper(Address, addresses)
+
def test_basic(self):
+ self._eagerload_mappings()
+
User = self.classes.User
sess = create_session()
pass
def test_yield_per_and_execution_options(self):
+ self._eagerload_mappings()
+
User = self.classes.User
sess = create_session()
assert q._yield_per
eq_(q._execution_options, {"stream_results": True, "foo": "bar"})
- def test_no_joinedload(self):
+ def test_no_joinedload_opt(self):
+ self._eagerload_mappings()
+
User = self.classes.User
sess = create_session()
q = sess.query(User).options(joinedload("addresses")).yield_per(1)
assert_raises_message(
sa_exc.InvalidRequestError,
"The yield_per Query option is currently not compatible with "
- "joined eager loading. Please specify ",
+ "joined collection eager loading. Please specify ",
q.all
)
- def test_no_subqueryload(self):
+ def test_no_subqueryload_opt(self):
+ self._eagerload_mappings()
+
User = self.classes.User
sess = create_session()
q = sess.query(User).options(subqueryload("addresses")).yield_per(1)
q.all
)
- def test_eagerload_disable(self):
+ def test_no_subqueryload_mapping(self):
+ self._eagerload_mappings(addresses_lazy="subquery")
+
+ User = self.classes.User
+ sess = create_session()
+ q = sess.query(User).yield_per(1)
+ assert_raises_message(
+ sa_exc.InvalidRequestError,
+ "The yield_per Query option is currently not compatible with "
+ "subquery eager loading. Please specify ",
+ q.all
+ )
+
+ def test_joinedload_m2o_ok(self):
+ self._eagerload_mappings(user_lazy="joined")
+ Address = self.classes.Address
+ sess = create_session()
+ q = sess.query(Address).yield_per(1)
+ q.all()
+
+ def test_eagerload_opt_disable(self):
+ self._eagerload_mappings()
+
User = self.classes.User
sess = create_session()
q = sess.query(User).options(subqueryload("addresses")).\
enable_eagerloads(False).yield_per(1)
q.all()
+ def test_m2o_joinedload_not_others(self):
+ self._eagerload_mappings(addresses_lazy="joined")
+ Address = self.classes.Address
+ sess = create_session()
+ q = sess.query(Address).options(
+ lazyload('*'), joinedload("user")).yield_per(1).filter_by(id=1)
+
+ def go():
+ result = q.all()
+ assert result[0].user
+ self.assert_sql_count(testing.db, go, 1)
+
class HintsTest(QueryTest, AssertsCompiledSQL):
def test_hints(self):