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.



Hibernate. A Developer's Notebook
Hibernate: A Developers Notebook
ISBN: 0596006969
EAN: 2147483647
Year: 2003
Pages: 65
Authors: James Elliott

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net