![]() | ![]() |
![]() |
| Project | Ver 1.1 | Ver 1.2 | JDO | JPA | Guides | Tools |
| 1.1 | Preparation | O/R Mapping | Runtime | Extensions | Developer |
Other sections have discussed the persistent of objects. Once you have persisted objects you need to query them. For example if you have a web application representing an online store, the user asks to see all products of a particular type, ordered by the price. This requires you to query the datastore for these products.
The JDO specifications (ver 1.0.1 and ver 2.0) require that implementations provide a Query capability using its own query
language (JDOQL). JDOQL is oriented around the objects that are persisted, and provides an interface for
selecting these objects within the framework of a query. JPOX provides such a JDOQL Query mechanism. The JDO 2.0
specification requires that implementations provide a SQL query mechanism (for datastores that
support SQL). JPOX provides this. In addition, JPOX provides a query language that is positioned between
JDOQL and SQL that has SQL-like syntax yet allows access to the field names of classes -
JPOXSQL Which query language is used is down to the developer. The data-tier of an application could be written by a primarily Java developer, who would typically think in an object-oriented way and so would likely prefer JDOQL. On the other hand the data-tier could be written by a datastore developer who is more familiar with SQL concepts and so could easily make more use of SQL. This is the power of an implementation like JPOX in that it provides the flexibility for different people to develop the data-tier utilising their own skills to the full without having to learn totally new concepts.
Let's now try to understand the Query interface in JDO
Query query = pm.newQuery("javax.jdo.query.JDOQL", "SELECT FROM org.jpox.MyClass WHERE param2 < threshold");
query.declareImports("import java.util.Date");
query.declareParameters("Date threshold");
query.setOrdering("param1 ascending");
List results = (List)query.execute(my_threshold);In this Query, we select our query language (JDOQL in this case), and the query is specified to return all objects of type org.jpox.MyClass (or subclasses) which have the field param2 less than some threshold value. We've specified the query like this because we want to pass the threshold value in dynamically. We then import the type of our threshold parameter, and the parameter itself, and set the ordering of the results from the Query to be in ascending order of some field param1. The Query is then executed, passing in the threshold value. The example is to highlight the typical methods specified for a Query. Clearly you may only specify the Query line if you wanted something very simple. The result of the Query is cast to a List since in this case it returns a List of results.
As we've mentioned, JPOX provides 3 query languages for the user. The most portable, provided across all datastores is JDOQL. Then we have one using the RDBMS query language SQL. In addition JPOX provides its own extension to SQL called JPOXSQL. The latter is non-portable across JDO implementations, and so by using it you would be reducing the portability of your JDO application. The 3 languages have clear differences in their syntax, but also in the application of the various methods on the Query. This table attempts to highlight the differences.
![]() The query described above is constructed dynamically. Queries of that form are perfect for situations like a web system where the user selects something and you want to present them with particular information based on their selections. There do however exist other types of situation where you know a particular query will be needed. In this case it isn't desirable to have to construct it at runtime. This functionality is added in the JDO 2.0 specification, allowing the user to specify queries in the JDO Meta-Data. To highlight how to do this, lets say we have a class called Product (something to sell in a store). We define the JDO Meta-Data for the class in the normal way, but we also have some query that we know we will require, so we define the following in the Meta-Data.
<jdo>
<package name="org.jpox.example">
<class name="Product">
...
<query name="SoldOut" language="javax.jdo.query.JDOQL"><![CDATA[
SELECT FROM org.jpox.example.Product WHERE status == "Sold Out"
]]></query>
</class>
</package>
</jdo>So we have a query called "SoldOut" defined for the class org.jpox.example.Product that returns all Product (and subclasses) that have a status of "Sold Out". So in our application all we need to do now is Query query = pm.newNamedQuery(org.jpox.example.Product.class,"SoldOut"); List results = (List)query.execute(); Please note that this syntax is based around the single-string form of JDOQL and applies to JPOX 1.1.0-beta-1 onwards. You now have the means to use the 2 principal types of queries in JDO. Please proceed to the sections specific to JDOQL and SQL for details on the precise nature of the query for these languages. See also :-
When you perform a query, using JDOQL or SQL the query will, in general, return a List of objects. These objects are by default of the same type as the candidate class. This is good for the majority of situations but there are some situations where you would like to control the output object. This can be achieved by specifying the Result Class. query.setResultClass(myResultClass); The Result Class has to meet certain requirements. These are
Where you have a query returning a single field, you could specify the Result Class to be one of the first group for example. Where your query returns multiple fields then you can set the Result Class to be your own class. So we could have a query like this
Query query = pm.newQuery(pm.getExtent(org.jpox.samples.Payment.class,false));
query.setFilter("amount > 10.0");
query.setResultClass(Price.class);
query.setResult("amount, currency");
List results = (List)query.execute();and we define our Result Class Price as follows
public class Price
{
protected double amount = 0.0;
protected String currency = null;
public Price(double amount, String currency)
{
this.amount = amount;
this.currency = currency;
}
...
}In this case our query is returning 2 fields (a Double and a String), and these map onto the constructor arguments, so JPOX will create objects of the Price class using that constructor. We could have provided a class with public fields instead, or provided setXXX methods or a put method. They all work in the same way.
![]() When a Query is executed it executes SQL in the datastore, which returns a ResultSet. JPOX could clearly read all results from this ResultSet in one go and return them all to the user, or could allow control over this fetching process. JDO2 provides a fetch size on the Fetch Plan to allow this control. You would set this as follows Query q = pm.newQuery(...); q.getFetchPlan().setFetchSize(FetchPlan.FETCH_SIZE_OPTIMAL); fetch size has 3 possible values.
In addition to the number of objects fetched, you can also control which fields are fetched for each object of the candidate type. This is controlled via the FetchPlan. See also Fetch Groups. ![]() JPOX also allows an extension to give further control. As mentioned above, when the transaction containing the Query is committed, all remaining results are read so that they can then be accessed later (meaning that the query is still usable). Where you have a large result set and you don't want this behaviour you can turn it off by specifying a Query extension q.addExtension("org.jpox.query.loadResultsAtCommit", "false");so when the transaction is committed, no more results will be available from the query.
![]() JPOX provides a useful extension to JDO queries by allowing control over the timeout of the query. So, for example, if you have a query that can cause problems in terms of the time taken, you can set a timeout on the query to retain the usability of your application. A JDO2 standard way of doing this (from 1.1.0-beta-6) for each query is to do query.addExtension("org.jpox.query.timeout","20");The value passed in is in seconds. You can also specify this for all queries using a PMF property "org.jpox.query.timeout".
![]() JPOX provides a useful extension to JDO by allowing control over the ResultSet's that are created by queries. You have at your convenience 4 properties that give you the power to control whether the result set is read only, whether it can be read forward only, the number of rows to be fetched etc. You can specify these on a per-Query basis (from version 1.1.0-beta-6) as follows
query.addExtension("org.jpox.query.fetchSize", "20");
query.addExtension("org.jpox.query.fetchDirection", "forward");
query.addExtension("org.jpox.query.resultSetType", "scroll-insensitive");
query.addExtension("org.jpox.query.resultSetConcurrency", "read-only");Alternatively you can specify these on the PersistenceManagerFactory so that they apply to all queries for that PMF. Again, the properties are
Bear in mind that not all JDBC drivers support all of the possible values for these options. That said, they do add a degree of control that is often useful. |