Core Java Data Objects

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:

  • Store the JDO identity of an object.

  • Iterate through potentially large collections of object graphs to locate a few objects that might be useful to the application. For example, if the previous snippet were applied to Stock objects that had a symbol attribute, the application would need to iterate through all the Stocks and compare the symbol until it found the one it was interested in!

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:

  1. The candidate class: This corresponds to the highest level in the class inheritance hierarchy to which the results must belong. This can be conceptually thought of as the branch where the JDO implementation will prune the class inheritance tree. For example, in Figure 6-4, if the application were only interested in finding specific Employees, then the candidate class would be Employee rather than People. If the application were interested in finding gold customers, then the class would be Gold, rather than Customers or People.

    Figure 6-4. Deciding on the candidate class.

  2. The candidate collection: The candidate collection is a Collection or Extent of objects from a corresponding candidate class that are present in the data-store. An application can pass a candidate collection that it constructs to the query facility and have that collection narrowed or filtered as a result of the query execution.

  3. The query filter: This is an expression that evaluates to some Boolean condition and is used to narrow the candidate collection returned as a result of the query execution.

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 Extent

Although 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.

Категории