The javax.jdo.Query
interface serves two functions:
object filtering and data retrieval. This chapter examines each in turn.
Note | |
---|---|
Kodo extends the standard |
JDO queries evaluate a group of candidate objects against a set of
conditions, eliminating the objects that don't match. We refer to
this as object filtering. The original group of
objects might be a Collection
of instances
you've already retrieved, or an Extent
. Recall
from Chapter 10, Extent that an Extent
represents all persistent instances of a certain class,
optionally including subclasses.
Filter conditions are specified in the JDO Query Language (JDOQL). The filtering process might take place in the datastore, or might be executed in memory. JDO does not mandate any one mechanism, and many implementations use a mixture of datastore and in-memory execution depending on the circumstances.
Basic object filtering utilizes the following Query
methods:
public void setClass (Class candidateClass); public void setCandidates (Extent candidates); public void setCandidates (Collection candidates); public void setFilter (String filter);
setClass
names the candidate class.
Candidate objects that are not assignable to the candidate
class cannot match the filter.
The two setCandidates
methods specify
the set of objects to evaluate. If you supply an
Extent
, you don't need to also call
setClass
; the Query
inherits the
Extent
's candidate class. Reciprocally,
if you call setClass
but do not call
either setCandidates
method, the query
candidates default to the Extent
of the
candidate class, including subclasses.
setFilter
accepts a JDOQL string
establishing the conditions an object must meet to be included
in the query results. As you'll see shortly, JDOQL looks
exactly like a Java boolean expression using the candidate
class' persistent fields and relations. When you don't set a
filter explicitly, it defaults to the simplest possible boolean
expression: true
. In this case, all
candidate objects assignable to the candidate class match
the query.
Let's see an example of basic object filtering in action. Our example draws on the following subset of the object model defined in Chapter 5, Metadata. We use this model subset throughout this chapter.
Example 11.1. Filtering
The following code processes all Magazine
objects in the database whose price is greater than 10 dollars.
PersistenceManager pm = ...; Query query = pm.newQuery (); query.setClass (Magazine.class); query.setCandidates (pm.getExtent (Magazine.class, true)); query.setFilter ("this.price > 10"); List mags = (List) query.execute (); for (Iterator itr = mags.iterator (); itr.hasNext ();) processMagazine ((Magazine) itr.next ()); query.close (mags);
The code above is technically correct, but could be much more
concise. First, remember that setting a candidate class defaults
the candidates to the Extent
of that class,
and vice versa. So we
don't need both the setClass
and setCandidates
calls. We can also get
rid of the this
qualifier on price
in our filter string, since unqualified field names are
already assumed to belong to the current object, just as in Java
code. Finally, we can take advantage of the fact that
PersistenceManager
overloads the
newQuery
method to tighten our code
further. Here is the revised version:
PersistenceManager pm = ...; Query query = pm.newQuery (Magazine.class, "price > 10"); List mags = (List) query.execute (); for (Iterator itr = mags.iterator (); itr.hasNext ();) processMagazine ((Magazine) itr.next ()); query.close (mags);
The filter above is rather basic. Before moving on to more advanced queries, though, we need to dive into the details of JDOQL.