9.1 Writing HQL Queries
We've already shown that you can get by with fewer pieces in an HQL query than you might be used to in SQL (the queries we've been using, such as those in Chapter 3, have
generally
omitted the "select" clause). In fact, the only thing you really
need
to specify is the class in which you're interested. Example 9-1 shows a minimal query that's a
perfectly
valid way to get a list of all
Track
instances
persisted
in the database.
NOTE
HQL stands for Hibernate Query Language. And SQL? It depends who you ask.
Example 9-1. The simplest HQL query
from Track
There's not much to it, is there? This is the HQL equivalent of Example 8-1, in which we built a criteria query on the
Track
class and supplied no criteria.
By default, Hibernate automatically "imports" the names of each class you map, which means you don't have to provide a fully qualified package name when you want to use it, the simple class name is enough. As long as you've not mapped more than one class with the same
name
, you don't need to use fully qualified class
names
in your queries. You are
certainly
free to do so if you prefer ”as I have in this book to help readers remember that the queries are
expressed
in terms of Java data beans and their properties,
not
database tables and
columns
(like you'd find in SQL). Example 9-2 produces precisely the same result as our first query.
Example 9-2. Explicit package naming, but still pretty simple
from com.oreilly.hh.Track
If you do have more than one mapped class with the same name, you can either use the fully qualified package name to refer to each, or you can assign an alternate name for one or both classes using an
import
tag in their mapping documents. You can also
turn
off the auto-import facility for a mapping file by adding
auto-import="false"
to the
hibernatemapping
tag's attributes.
|
You're probably used to queries being case-insensitive, since SQL behaves this way. For the most part, HQL acts the same, with the important exceptions of class and property names. Just as in the rest of Java, these are case-sensitive, so you must get the capitalization right.
|
|
Let's look at an extreme example of how HQL
differs
from SQL, by pushing its polymorphic query capability to its logical limit.
9.1.1 How do I do that?
A powerful way to highlight the fundamental difference between SQL and HQL is to consider what happens when you query
"from java.lang.Object"
. At first glance this might not even seem to make sense! In fact, Hibernate supports queries that return polymorphic results. If you've got mapped classes that extend each other, or have some shared
ancestor
or interface, whether you've mapped the classes to the same table or to different tables, you can query the superclass. Since every Java object extends
Object
, this query asks Hibernate to return every single entity it
knows
about in the database.
We can test this by making a quick variant of our query test. Copy
QueryTest.java
to
QueryTest3.java
, and make the changes shown in Example 9-3 (most of the changes, which don't show up in the example, involve deleting example queries we don't need here).
Example 9-3. Look, Toto, we're not in SQL anymore
1 package com.oreilly.hh;
2
3 import net.sf.hibernate.*;
4 import net.sf.hibernate.cfg.Configuration;
5
6 import java.util.*;
7
8 /**
9 *
Retrieve all persistent objects
10 */
11 public class
QueryTest3
{
12
13 /**
14 * Look up and print
all entities
when invoked from the command line.
15 */
16 public static void main(String args[]) throws Exception {
17 // Create a configuration based on the properties file we've put
18 // in the standard place.
19 Configuration config = new Configuration();
20
21 // Tell it about the classes we want mapped, taking advantage of
22 // the way we've named their mapping documents.
23 config.addClass(Track.class).addClass(Artist.class);
24
config.addClass(Album.class);
25
26 // Get the session factory we can use for persistence
27 SessionFactory sessionFactory = config.buildSessionFactory();
28
29 // Ask for a session using the JDBC information we've configured
30 Session session = sessionFactory.openSession();
31 try {
32 // Print
every mapped object in the database
33 List
all
=
session.find("from java.lang.Object");
34 for (ListIterator iter =
all
.listIterator() ;
35 iter.hasNext() ; ) {
36
System.out.println(iter.next());
37 }
38 } finally {
39 // No matter what, close the session
40 session.close();
41 }
42
43 // Clean up after ourselves
44 sessionFactory.close();
45 }
46 }
We added line 24 because Hibernate will only return objects whose mappings it has been asked to load, and we'd like to see everything we can put in the database. To be sure you've got all the sample data created, run
ant schema ctest atest
. Line 33 invokes the odd and powerful query, and line 36 prints what we've found. We can't do much more than call
toString()
on the objects we get back because we don't know what they might be.
Object
is not very deep as a shared interface.
There's one more step we need to take before we can run this. Add another target to
build.xml
, as shown in Example 9-4.
NOTE
As usual, these examples assume you've set up the environment by following the
preceding
chapters. You can also just use the downloadable sample source for this chapter.
Example 9-4. Invoking the ¼ber-query
<target name="qtest3" description="Retrieve all mapped objects"
depends="compile">
<java classname="com.oreilly.hh.QueryTest3" fork="true">
<classpath refid="project.class.path"/>
<java>
</target>
Then you can test it by running
ant qtest3
. You'll see results like Example 9-5.
Example 9-5. Everything Hibernate can find
%
ant qtest3
Buildfile: build.xml
prepare:
compile:
[javac] Compiling 1 source file to /Users/jim/Documents/Work/OReilly/
Hibernate/Examples/ch09/classes
qtest3:
[java] com.oreilly.hh.Album@397cea[id=0,title=Counterfeit e.p.,tracks=[com.
oreilly.hh.AlbumTrack@5e60f2[track=com.oreilly.hh.
Track@aaa10[id=7,title=Compulsion,sourceMedia=Compact Disc]], com.oreilly.hh.
AlbumTrack@2ed1e8[track=com.oreilly.hh.Track@231e35[id=8,title=In a Manner of
Speaking,sourceMedia=Compact Disc]], com.oreilly.hh.AlbumTrack@d6f84a[track=com.
oreilly.hh.Track@9432e0[id=9,title=Smile in the Crowd,sourceMedia=Compact Disc]],
com.oreilly.hh.AlbumTrack@46ca65[track=com.oreilly.hh.
Track@9830bc[id=10,title=Gone,sourceMedia=Compact Disc]], com.oreilly.hh.
AlbumTrack@91e365[track=com.oreilly.hh.Track@a79447[id=11,title=Never Turn Your
Back on Mother Earth,sourceMedia=Compact Disc]], com.oreilly.hh.
AlbumTrack@e823ac[track=com.oreilly.hh.Track@f801c4[id=12,title=Motherless
Child,sourceMedia=Compact Disc]]]]
[java] com.oreilly.hh.Artist@e7736c[id=0,name=PPK,actualArtist=<null>]
[java] com.oreilly.hh.Artist@a59727[id=1,name=The
Buggles,actualArtist=<null>]
[java] com.oreilly.hh.Artist@1f7fbe[id=2,name=Laurie
Anderson,actualArtist=<null>]
[java] com.oreilly.hh.Artist@f42d53[id=3,name=William
Orbit,actualArtist=<null>]
[java] com.oreilly.hh.Artist@ba63a2[id=4,name=Ferry
Corsten,actualArtist=<null>]
[java] com.oreilly.hh.Artist@e668c2[id=5,name=Samuel
Barber,actualArtist=<null>]
[java] com.oreilly.hh.Artist@d67d61[id=6,name=ATB,actualArtist=<null>]
[java] com.oreilly.hh.Artist@e9a555[id=7,name=Pulp
Victim,actualArtist=<null>]
[java] com.oreilly.hh.Artist@6a4aef[id=8,name=Martin L.
Gore,actualArtist=<null>]
[java] com.oreilly.hh.Track@4dba7f[id=0,title=Russian
Trance,sourceMedia=Compact Disc]
[java] com.oreilly.hh.Track@906563[id=1,title=Video Killed the Radio
Star,sourceMedia=VHS Videocassette Tape]
[java] com.oreilly.hh.Track@f068b9[id=2,title=Gravity's
Angel,sourceMedia=Compact Disc]
[java] com.oreilly.hh.Track@6b54ef[id=3,title=Adagio for Strings (Ferry
Corsten Remix),sourceMedia=Compact Disc]
[java] com.oreilly.hh.Track@954549[id=4,title=Adagio for Strings (ATB
Remix),sourceMedia=Compact Disc]
[java] com.oreilly.hh.Track@f7dab1[id=5,title=The World
'99,sourceMedia=Digital Audio Stream]
[java] com.oreilly.hh.Track@36d1d7[id=6,title=Test Tone 1,sourceMedia=<null>]
[java] com.oreilly.hh.Track@aaa10[id=7,title=Compulsion,sourceMedia=Compact
Disc]
[java] com.oreilly.hh.Track@231e35[id=8,title=In a Manner of
Speaking,sourceMedia=Compact Disc]
[java] com.oreilly.hh.Track@9432e0[id=9,title=Smile in the
Crowd,sourceMedia=Compact Disc]
[java] com.oreilly.hh.Track@9830bc[id=10,title=Gone,sourceMedia=Compact
Disc]
[java] com.oreilly.hh.Track@a79447[id=11,title=Never Turn Your Back on Mother
Earth,sourceMedia=Compact Disc]
[java] com.oreilly.hh.Track@f801c4[id=12,title=Motherless
Child,sourceMedia=Compact Disc]
BUILD SUCCESSFUL
Total time: 17 seconds
9.1.2 What just
happened
?
Well, it's pretty
remarkable
if you think about it, because Hibernate had to do several separate SQL queries in order to obtain the results for us. A whole lot of work went on behind the scenes to hand us that list of every known persisted entity. Although it's hard to imagine a situation where you'll actually need to do something exactly like this, it certainly highlights some of the interesting capabilities of HQL and Hibernate.
And there are certainly times when slightly less comprehensive queries will be very useful to you, so it's worth keeping in mind that tablespanning polymorphic queries are not only possible, but easy to use.
There are some limitations that come into play when you run an HQL query that requires multiple separate SQL queries to implement. You can't use
order by
clauses to
sort
the entire set of results, nor can you use the
Query
interface's
scroll()
method to walk through them.
9.1.3 What about...
...Associations and joins? These are easy to work with as well. You can traverse associations by simply following the property chain, using periods as delimiters. To help you refer to a particular entity in your query expressions, HQL lets you assign aliases, just like SQL. This is particularly important if you want to refer to two separate entities of the same class, for example:
from com.oreilly.hh.Track as track1
which is equivalent to
from com.oreilly.hh.Track track1
The version you'll use will most likely depend on what you're used to, or the style guidelines established for your project.
We'll see examples of joins below, once we introduce enough other HQL elements to make them interesting.
|