Obtaining specific objects by using their JDO Identity or obtaining a collection of objects through the use of an Extent is simple and convenient . However, both these techniques have drawbacks. It is not always possible or desirable to do the following:
The API portion of the query facility in JDO consists primarily of the Query interface shown in Figure 6-3. This was also introduced in Chapters 3 and 5. Figure 6-3. The javax.jdo.Query interface.
The Query interface abstracts the concept of interrogating the underlying data-store and retrieving objects that might match specific criteria. Three terms are important in this regard:
Let's rework the previous example to incorporate the Query facility. Note that the results produced by the code shown below are identical to the earlier example. It returns all persistent Author objects because no Extent or filter has been specified in the query. PersistenceManager pm = pmf.getPersistenceManager(); Transaction tx = pm.currentTransaction(); tx.begin(); Query query = pm.newQuery(Author.class); Collection results = (Collection) query.execute(); if (results.isEmpty()) System.out.println("No results found"); else { Iterator iter = results.iterator(); while (iter.hasNext()) { Author author = (Author) iter.next(); String name = author.getName(); System.out.println("Author's name is " + name); } } query.closeAll(); tx.commit(); When the Query is executed via the execute() method, the results are contained in an unmodifiable or immutable Collection. The actual method signature is declared to return an Object to allow for future or vendor extensions, but the application code must explicitly cast the result of the execute() method to a Collection. Elements of the collection can be accessed through the Iterator, but any attempt to change the collection causes an UnsupportedOperationException to be thrown. The Collection object containing as the query results is required only to support the iterator() method because the implementation of the class is up to the vendor. For example, a vendor using a relational database may not be able to support the size() method because the database rows may be available only the first time they are accessed. For this reason, the size() method may return Integer.MAX_VALUE. The results of a query may hold onto resources linked to the underlying datastore (such as connections). Therefore, all the query instances must be closed explicitly when the results are no longer needed. The individual result can be closed using the close(Object queryResult) method, or all open results associated with the Query can be closed at once with the closeAll() method. The idea of closing Query results is conceptually analogous to the way the close() method works for the java.sql.ResultSet object in JDBC. 6.3.1 Queries with an ExtentAlthough the Extent by itself may not be very meaningful, when used alongside the Query, it can be used to refine the results. The Query can be refined to return only instances of a class and its subclasses by specifying an Extent when the Query is constructed using the factory method. Code to accomplish this is shown below: tx.begin(); Extent extent = pm.getExtent(Author.class, true); Query query= pm.newQuery(extent); Collection results=(Collection)query.execute(); Iterator iter = results.iterator(); while (iter.hasNext()) { Author author = (Author) iter.next(); String name = author.getName(); System.out.println("Author's name is '" + name + "'."); } query.closeAll(); tx.commit(); Again, the results produced by the above code are identical to those produced in Section 6.2 because the Extent specifies the Author class. The preceding discussion was meant to introduce you to the API itself. Before we look at queries and the API in greater detail, let's look at the second part of the query facility ”JDOQL, the query language. We return then to the API and look at examples in greater detail by incorporating the query language in them. |