From: Mike Bayer Date: Sat, 23 Jul 2011 16:27:09 +0000 (-0400) Subject: - document query.get(), ObjectDeletedError fully, [ticket:2146] X-Git-Tag: rel_0_7_2~17 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a3705cd17b647de71ea8adc662f6e6808c37518b;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - document query.get(), ObjectDeletedError fully, [ticket:2146] --- diff --git a/doc/build/orm/loading.rst b/doc/build/orm/loading.rst index 3b3d1ff075..45b94191f7 100644 --- a/doc/build/orm/loading.rst +++ b/doc/build/orm/loading.rst @@ -330,7 +330,7 @@ references a scalar many-to-one reference. * When using the default lazy loading, a load of 100 objects will like in the case of the collection emit as many as 101 SQL statements. However - there is a significant exception to this, in that if the many-to-one reference is a simple foreign key reference to the target's primary key, each - reference will be checked first in the current identity map using ``query.get()``. So here, + reference will be checked first in the current identity map using :meth:`.Query.get`. So here, if the collection of objects references a relatively small set of target objects, or the full set of possible target objects have already been loaded into the session and are strongly referenced, using the default of `lazy='select'` is by far the most efficient way to go. diff --git a/doc/build/orm/tutorial.rst b/doc/build/orm/tutorial.rst index 410e1a0692..af44e4da83 100644 --- a/doc/build/orm/tutorial.rst +++ b/doc/build/orm/tutorial.rst @@ -1491,7 +1491,7 @@ their parent: >>> mapper(Address, addresses_table) # doctest: +ELLIPSIS -Now when we load Jack (below using :meth:`~Query.get`, which loads by primary key), +Now when we load Jack (below using :meth:`~.Query.get`, which loads by primary key), removing an address from his ``addresses`` collection will result in that ``Address`` being deleted: diff --git a/lib/sqlalchemy/orm/exc.py b/lib/sqlalchemy/orm/exc.py index 3bfb2708cd..1812f0d720 100644 --- a/lib/sqlalchemy/orm/exc.py +++ b/lib/sqlalchemy/orm/exc.py @@ -77,7 +77,24 @@ class UnmappedClassError(UnmappedError): class ObjectDeletedError(sa.exc.InvalidRequestError): - """An refresh() operation failed to re-retrieve an object's row.""" + """A refresh operation failed to retrieve the database + row corresponding to an object's known primary key identity. + + A refresh operation proceeds when an expired attribute is + accessed on an object, or when :meth:`.Query.get` is + used to retrieve an object which is, upon retrieval, detected + as expired. A SELECT is emitted for the target row + based on primary key; if no row is returned, this + exception is raised. + + The true meaning of this exception is simply that + no row exists for the primary key identifier associated + with a persistent object. The row may have been + deleted, or in some cases the primary key updated + to a new value, outside of the ORM's management of the target + object. + + """ class UnmappedColumnError(sa.exc.InvalidRequestError): diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py index 701b376af9..8d64d69b41 100644 --- a/lib/sqlalchemy/orm/query.py +++ b/lib/sqlalchemy/orm/query.py @@ -635,22 +635,61 @@ class Query(object): self._execution_options['stream_results'] = True def get(self, ident): - """Return an instance of the object based on the - given identifier, or ``None`` if not found. - - The ``ident`` argument is a scalar or tuple of - primary key column values - in the order of the mapper's "primary key" setting, which - defaults to the list of primary key columns for the - mapped :class:`.Table`. + """Return an instance based on the given primary key identifier, + or ``None`` if not found. + + E.g.:: + + my_user = session.query(User).get(5) + + some_object = session.query(VersionedFoo).get((5, 10)) + + :meth:`~.Query.get` is special in that it provides direct + access to the identity map of the owning :class:`.Session`. + If the given primary key identifier is present + in the local identity map, the object is returned + directly from this collection and no SQL is emitted, + unless the object has been marked fully expired. + If not present, + a SELECT is performed in order to locate the object. + + :meth:`~.Query.get` also will perform a check if + the object is present in the identity map and + marked as expired - a SELECT + is emitted to refresh the object as well as to + ensure that the row is still present. + If not, :class:`~sqlalchemy.orm.exc.ObjectDeletedError` is raised. + + :meth:`~.Query.get` is only used to return a single + mapped instance, not multiple instances or + individual column constructs, and strictly + on a single primary key value. The originating + :class:`.Query` must be constructed in this way, + i.e. against a single mapped entity, + with no additional filtering criterion. Loading + options via :meth:`~.Query.options` may be applied + however, and will be used if the object is not + yet locally present. + + A lazy-loading, many-to-one attribute configured + by :func:`.relationship`, using a simple + foreign-key-to-primary-key criterion, will also use an + operation equivalent to :meth:`~.Query.get` in order to retrieve + the target value from the local identity map + before querying the database. See :ref:`loading_toplevel` + for further details on relationship loading. + + :param ident: A scalar or tuple value representing + the primary key. For a composite primary key, + the order of identifiers corresponds in most cases + to that of the mapped :class:`.Table` object's + primary key columns. For a :func:`.mapper` that + was given the ``primary key`` argument during + construction, the order of identifiers corresponds + to the elements present in this collection. + + :return: The object instance, or ``None``. - :meth:`get` returns only a single mapped instance, or - ``None``. It is not intended to return rows or scalar - column values, therefore the :class:`.Query` must be - constructed only against a single mapper or mapped class, - not a SQL expression or multiple entities. - Other usages raise an error. - """ # convert composite types to individual args