9.2 Creating and Initializing a Query
The PersistenceManager interface contains a set of
Query factory methods used to construct
Query instances. They mainly differ in which query
components are initialized. Query instances may be
constructed at any time before a
PersistenceManager is closed.
The following PersistenceManager method constructs
an empty Query instance with none of the
components initialized:
Query newQuery( );
The following PersistenceManager methods construct
a Query instance with an Extent
as the collection of candidate instances:
Query newQuery(Extent candidates);
Query newQuery(Extent candidates, String filter);
The candidate class is initialized with the class of the
Extent. The second method also initializes the
query filter. We used this second method when we constructed the
Query on line [3] in our
example.
Alternatively, a collection can serve as the set of candidate
instances in a query. The following
PersistenceManager methods construct a
Query instance with a
Collection as the set of candidate instances:
Query newQuery(Class candidateClass, Collection candidates);
Query newQuery(Class candidateClass, Collection candidates, String filter);
When performing a query on a collection, it is necessary to specify
the class of the candidate instances explicitly.
The elements in the collection should be persistent instances
associated with the same PersistenceManager as the
Query instance. If the collection contains
instances associated with another
PersistenceManager, a
JDOUserException
is thrown during execute( ). An implementation
might allow you to perform a query on a collection of transient
instances, but this is a nonportable, implementation-specific
capability.
You can also construct a Query instance without
initializing the set of candidate instances by calling one of the
following PersistenceManager methods:
Query newQuery(Class candidateClass);
Query newQuery(Class candidateClass, String filter);
Once the Query is constructed, the collection of
candidate instances can be set by calling one of its two
setCandidates(
) methods, or it will default to the extent of the
candidate class (including subclasses) identified by the
candidateClass parameter passed to one of these
two newQuery( ) methods. This allows you to
perform a query without having to deal with an
Extent.
A Query instance can be serialized. This allows
you to create queries, serialize them, store them on disk, and later
use them in a different execution environment. The serialized fields
include the candidate class, the filter, parameter declarations,
variable declarations, imports, the IgnoreCache
setting, and the ordering specification. Of course, the candidate
collection is not serialized with the Query
instance. When a serialized Query instance is
restored, it is no longer associated with its former
PersistenceManager.
The following PersistenceManager method is used to
construct a new Query instance from an existing or
deserialized Query instance:
Query newQuery(Object query);
The query parameter might be a restored
Query instance that was serialized from the same
JDO implementation but a different execution environment, or it might
be currently bound to a PersistenceManager from
the same implementation. All of the query components from the
query parameter are copied to the new
Query instance, except for the candidate
Collection or Extent. You can
initialize this query component with a call to
setCandidates( ).
Lastly, you can use the following
PersistenceManager method to construct a
Query that uses a query language different than
JDOQL:
Query newQuery(String language, Object query);
The Query instance is constructed using the
specified language and query
parameters. The language parameter specifies the
query language used by the query parameter. The
query instance must be an instance of a class
defined by the query language. For JDOQL, the value of the
language parameter is
"javax.jdo.query.JDOQL". The JDO specification
does not specify other query languages that can be specified and used
by this method; it is implementation-specific.
Once you have constructed a Query, you can access
the PersistenceManager instance you originally
used to create the Query instance by calling the
following Query method:
PersistenceManager getPersistenceManager( );
A null is returned if the Query
was restored from a serialized form.
You can have multiple Query instances active
simultaneously in the same PersistenceManager
instance. The queries may be executed simultaneously by different
threads, but the implementation may execute them serially. In either
case, the execution is thread-safe.
The Query interface provides methods to bind query
components before the query is executed. Their parameters replace the
previously set query component (i.e., the methods are not additive).
For example, if a query needs multiple variables, they all must be
specified in the same call to
declareVariables(
).
You can use the following Query methods to set the
required components of the query, including the
candidate
class, candidate set, and
filter:
void setClass(Class candidateClass);
void setCandidates(Collection candidates);
void setCandidates(Extent candidates);
void setFilter(String filter);
If you specify an Extent as the set of candidate
instances, the candidate class defaults to the class of the
Extent. When you perform a query on a collection,
you need to specify the class of the candidate instances explicitly.
In other words, if you pass a Collection to
setCandidates( ), you must also call
setClass(
) before compiling or executing the query.
If you specify the class of candidate instances but do not provide
the collection of candidate instances, the collection defaults to the
Extent of the candidate class, with subclass
instances included. Therefore, each of the following approaches
produces an equivalent Query initialization:
// Approach 1
Query query = pm.newQuery(MediaContent.class);
// Approach 2
Query query = pm.newQuery( );
query.setClass(MediaContent.class);
// Approach 3
Query query = pm.newQuery(pm.getExtent(MediaContent.class, true));
// Approach 4
Query query = pm.newQuery( );
query.setCandidates(pm.getExtent(MediaContent.class, true));
If a collection serving as the set of candidates has an element that
has been deleted by a call to deletePersistent( ),
the element is ignored. If instances are added or removed from the
candidates collection after
setCandidates( ) is called, it is
implementation-specific whether those elements take part in the query
or a
NoSuchElementException
is thrown during execution of the query. So, you should not alter the
collection once it has been passed to setCandidates(
).
You declare query parameters, variables, and their types after the
Query has been constructed by calling the
following methods:
void declareParameters(String parameters);
void declareVariables(String variables);
void declareImports(String imports);
The following method initializes the ordering specification:
void setOrdering(String ordering);
We cover each of these methods and their parameter syntax later in
this chapter.
|