9.1 Query ComponentsThe JDO query facility applies a Boolean filter to a collection of candidate instances and returns the instances that evaluate to true . The collection of candidate instances can be either an Extent or a Collection . The class of candidate instances is another query component. Instances are returned in the query result only if they are instances of the candidate class. Let's begin by examining a method that performs a query that accesses Customer instances in the Media Mania model. We assume that an application has started a transaction and called queryCustomers( ) , passing the PersistenceManager instance and values to filter the Customer instances to those whose addresses are in a specific city and state. public static void queryCustomers(PersistenceManager pm, String city, String state) { Extent customerExtent = pm.getExtent(Customer.class, true); [1] String filter = "address.city == city && state == address.state"; [2] Query query = pm.newQuery(customerExtent, filter); [3] query.declareParameters("String city, String state"); [4] query.setOrdering( [5] "address.zipcode ascending, lastName ascending, firstName ascending"); Collection result = (Collection) query.execute(city, state); [6] Iterator iter = result.iterator( ); while (iter.hasNext( )) { [7] Customer customer = (Customer) iter.next( ); Address address = customer.getAddress( ); System.out.print(address.getZipcode( )); System.out.print(" "); System.out.print(customer.getFirstName( )); System.out.print(" "); System.out.print(customer.getLastName( )); System.out.print(" "); System.out.println(address.getStreet( )); } query.close(result); [8] } This code performs a query on the Customer extent, which we access on line [1] . When we create the Query instance on line [3] , we provide the Customer extent as the collection of candidate instances to be evaluated in the query. When you use an Extent , as we have here, it also identifies the class of the candidate instances. We use the candidate class to establish the namespace for the identifiers used in the query filter. Line [2] specifies the filter for the query. It uses the Customer field address and navigates to the associated Address instance to access the city and state fields. The city and state identifiers in the filter are query parameters, which are declared on line [4] . We access all Customer instances that live in a specific city and state. The Java == operator expresses equality, and the Java operator && performs a conditional AND operation. You will find JDOQL very easy to learn, because it uses Java operators and syntax. You also express your queries using the identifiers in your object model. On line [5] , we establish an ordering for the instances that are in the query result. First we order customers based on their ZIP code; we then order all customers in the same ZIP code by their last name and then first name , all in ascending order. This ordering specification is similar to SQL's ORDER BY clause. Line [6] executes the query. We pass the city and state method parameters to execute( ) as query parameters, which are also named city and state . It is not necessary for the method parameters to have the same names as the query parameters, but we do so to make it clear to anyone reading the code that they are associated. Line [4] declares the query parameters and their order. The order in this declaration establishes the order that the query parameter values should be passed to execute( ) on line [6] . The result of the query must be cast to a Collection in JDO 1.0.1. The execute( ) method is defined to return Object , to allow for future extensions that may return a single instance. In general, you should call iterator( ) only on the return value of execute( ) . Once we have an Iterator , we can iterate through all the returned Customer instances. The code also navigates from the returned Customer instance to its associated Address instance. Once we are done with the query result, we close it on line [8] . Every query requires three components:
The collection and class of the candidate instances and the query filter can be initialized when a Query is constructed by calling one of several newQuery( ) methods defined in the PersistenceManager interface (as we did on line [3] ). Once a Query has been constructed, all of the query components can be set; each has an associated set method. A query may also include the following components:
You need to create and initialize these query components before you execute a query. Query components can be initialized when a Query is constructed or via a set method provided for the query component. The order in which you initialize the query components before the Query is executed does not matter. |