Let's start by building a criteria query to find tracks shorter than a specified length, replacing the HQL we used in Example 3-9 and updating the code of Example 3-10.
The first thing we need to figure out is how to specify the kind of object we're interested in retrieving. There is no query language involved in building criteria queries. Instead, you build up a tree of
Criteria
objects describing what you want. The Hibernate
Session
acts as a factory for these criteria, and you start, conveniently enough, by specifying the type of objects you want to retrieve.
The session's
createCriteria()
method builds a criteria query that will return instances of the persistent class you supply as an argument. Easy enough. If you run the example at this point, of course, you'll see all the tracks in the database, since we haven't gotten around to
expressing
any actual
criteria
to limit our results yet (Example 8-2).
Example 8-2. Our fledgling criteria query returns all tracks
%
ant qtest
...
qtest:
[java] Track: "Russian Trance" (PPK) 00:03:30, from Compact Disc
[java] Track: "Video Killed the Radio Star" (The Buggles) 00:03:49, from VHS
Videocassette Tape
[java] Track: "Gravity's Angel" (Laurie Anderson) 00:06:06, from Compact Disc
[java] Track: "Adagio for Strings (Ferry Corsten Remix)" (Ferry Corsten,
William Orbit, Samuel Barber) 00:06:35, from Compact Disc
[java] Track: "Adagio for Strings (ATB Remix)" (ATB, William Orbit, Samuel
Barber) 00:07:39, from Compact Disc
[java] Track: "The World '99" (Ferry Corsten, Pulp Victim) 00:07:05, from
Digital Audio Stream
[java] Track: "Test Tone 1" 00:00:10
[java] Comment: Pink noise to test equalization
OK, easy enough. How about picking the tracks we want? Also easy! Add a new import statement at the top of the file:
import net.sf.hibernate.expression.*;
Then just add one more line to the method, as in Example 8-3.
Example 8-3. The criteria query that fully
replaces
the HQL version from Chapter 3
public static List tracksNoLongerThan(Time length, Session session)
throws HibernateException
{
Criteria criteria = session.createCriteria(Track.class);
criteria.add(Expression.le("playTime", length));
return criteria.list();
}
The
Expression
class acts as a factory for obtaining
Criterion
instances that can specify different kinds of constraints on your query. Its
le()
method creates a criterion that constrains a property to be less than or equal to a specified value. In this case we want the
Track's playTime
property to be no greater than the value passed in to the method. We add this to our set of desired criteria.
NOTE
Just like HQL, expressions are always in terms of object properties, not table
columns
.
We'll look at some other
Criterion
types available through
Expression
in the
next
section. Appendix B lists them all, and you can create your own
implementations
of the
Criterion
interface if you've got something new you want to support.
Running the query this time gives us just the tracks that are no more than seven minutes long, as
requested
by the
main()
method (Example 8-4).
Example 8-4. Results of our complete simple criteria query
%
ant qtest
...
qtest:
[java] Track: "Russian Trance" (PPK) 00:03:30, from Compact Disc
[java] Track: "Video Killed the Radio Star" (The Buggles) 00:03:49, from VHS
Videocassette Tape
[java] Track: "Gravity's Angel" (Laurie Anderson) 00:06:06, from Compact Disc
[java] Track: "Adagio for Strings (Ferry Corsten Remix)" (Ferry Corsten,
William Orbit, Samuel Barber) 00:06:35, from Compact Disc
[java] Track: "Test Tone 1" 00:00:10
[java] Comment: Pink noise to test equalization
A surprising number of the queries used to retrieve objects in real applications are very simple, and criteria queries are an extremely natural and compact way of expressing them in Java. Our new
tracksNoLongerThan()
method is actually shorter than it was in Example 3-10, and that version required a separate query (Example 3-9) to be added to the mapping document as well! Both approaches lead to the same patterns of underlying database access, so they are equally efficient at runtime.
In fact, you can make the code even more compact. The
add()
and
createCriteria()
methods
return the
Criteria
instance, so you can continue to manipulate it in the same Java statement. Taking advantage of that, we can boil the method down to the version in Example 8-5.
Example 8-5. An even more compact version of our criteria query
public static List tracksNoLongerThan(Time length, Session session)
throws HibernateException
{
return session.createCriteria(Track.class).
add(Expression.le("playTime", length)).list();
}
The style you choose is a trade-off between space and readability (although some people may find the compact,
run-on
version even more readable). Even though this is
marked
as an experimental API, it already looks extremely useful, and I expect to adopt it in many places.
8.1.2 What about...
...Sorting the list of results, or retrieving a subset of all matching objects? Like the
Query
interface, the
Criteria
interface lets you limit the number of results you get back (and choose where to start) by calling
setMaxResults()
and
setFirstResult()
. It also lets you control the order in which they're returned (which you'd do using an
order by
clause in an HQL query), as shown in Example 8-6.
Example 8-6. Sorting the results by title
public static List tracksNoLongerThan(Time length, Session session)
throws HibernateException
{
Criteria criteria = session.createCriteria(Track.class);
criteria.add(Expression.le("playTime", length));
criteria.addOrder(Order.asc("title"));
return criteria.list();
}
The
Order
class is just a way of representing orderings. It has two static factory methods,
asc()
and
desc()
, for creating
ascending
or descending orderings respectively. Each takes the
name
of the property to be sorted. The results of running this version are in Example 8-7.
Example 8-7. The sorted results
%
ant qtest
...
qtest:
[java] Track: "Adagio for Strings (Ferry Corsten Remix)" (Ferry Corsten,
William Orbit, Samuel Barber) 00:06:35, from Compact Disc
[java] Track: "Gravity's Angel" (Laurie Anderson) 00:06:06, from Compact Disc
[java] Track: "Russian Trance" (PPK) 00:03:30, from Compact Disc
[java] Track: "Test Tone 1" 00:00:10
[java] Comment: Pink noise to test equalization
[java] Track: "Video Killed the Radio Star" (The Buggles) 00:03:49, from VHS
Videocassette Tape
You can add more than one
Order
to the
Criteria
, and it will
sort
by each of them in
turn
(the first gets priority, and then if there are any results with the same value for that property, the second ordering is applied to them, and so on).