8.4 Querying by Example

     

If you don't want to worry about setting up expressions and criteria, but you've got an object that shows what you're looking for, you can use it as an example and have Hibernate build the criteria for you.

8.4.1 How do I do that?

Let's add another query method to QueryTest.java. Add the code of Example 8-16 to the top of the class where the other queries are.

Example 8-16. Using an example entity to populate a criteria query
 1  /**  2   * Retrieve any tracks that were obtained from a particular source  3   * media type.  4   *  5   * @param sourceMedia the media type of interest.  6   * @param session the Hibernate session that can retrieve data.  7   * @return a list of {@link Track}s meeting the media restriction.  8   * @throws HibernateException if there is a problem.  9   */ 10  public static List tracksFromMedia(SourceMedia media, Session session) 11      throws HibernateException 12  { 13      Track track = new Track(); 14      track.setSourceMedia(media); 15      Example example = Example.create(track); 16 17      Criteria criteria = session.createCriteria(Track.class); 18      criteria.add(example); 19      criteria.addOrder(Order.asc("title")); 20      return criteria.list(); 21  } 

Lines 13 and 14 create the example Track and set the sourceMedia property to represent what we're looking for. Lines 15 wraps it in an Example object. This object gives you some control over which properties will be used in building criteria and how strings are matched. The default behavior is that null properties are ignored, and that strings are compared in a case-sensitive and literal way. You can call example 's excludeZeroes() method if you want properties with a value of zero to be ignored too, or excludeNone() if even null properties are to be matched. An excludeProperty() method lets you explicitly ignore specific properties by name , but that's starting to get a lot like building criteria by hand. To tune string handling, there are ignoreCase() and enableLike() methods , which do just what they sound like.

Line 17 creates a criteria query, just like our other examples in this chapter, but we then add our example to it instead of using Expression to create a criterion . Hibernate takes care of translating example into the corresponding criteria. Lines 19 and 20 are just like our previous query methods: setting up a sort order, running the query, and returning the list of matching entities.

Once again we need to modify the main() method to call our new query. Let's find the tracks that came from CDs. Make the changes shown in Example 8-17.

Example 8-17. Changes to main() to call our example-driven query method
 ... // Ask for a session using the JDBC information we've configured Session session = sessionFactory.openSession(); try {     // Print  tracks that came from CDs  List tracks =  tracksFromMedia(SourceMedia.CD,  session);     for (ListIterator iter = tracks.listIterator() ; ... 

Running this version produces output like Example 8-18.

Example 8-18. Results of querying by example for tracks from CDs
 qtest:     [java] Track: "Adagio for Strings (ATB Remix)" (ATB, William Orbit, Samuel Barber) 00:07:39, 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: "Gravity's Angel" (Laurie Anderson) 00:06:06, from Compact Disc     [java] Track: "Russian Trance" (PPK) 00:03:30, from Compact Disc 

You might think this is something of a contrived example, in that we didn't actually have a handy Track object around to use as an example, and had to create one in the method. Well, perhaps... but there is a valuable reason to use this approach: it gives you even more compile-time checking than pure criteria queries. While any criteria query protects against syntactic runtime errors in HQL queries, you can still make mistakes in your property names , which won't be caught by the compiler, since they're just strings. When building example queries, you actually set property values using the mutator methods of the entity classes. This means if you make a typo, Java catches it at compile time.


As you might expect, you can use examples with subcriteria for associated objects, too. We could rewrite tracksWithArtistLike() so that it uses an example Artist rather than building its criterion 'by hand.' We'll need to call enableLike() on our example . Example 8-19 shows a concise way of doing this.

Example 8-19. Updating the artist name query to use an example artist
 public static List tracksWithArtistLike(String namePattern, Session session)     throws HibernateException {     Criteria criteria = session.createCriteria(Track.class);  Example example = Example.create(new Artist(namePattern, null, null));     criteria.createCriteria("artists").add(example.enableLike());  criteria.addOrder(Order.asc("title"));     return criteria.list(); } 

Remember that if you want to try running this you'll need to switch main() back to the way it was in Example 8-14.

NOTE

Criteria queries are pretty neat, aren't they? I like them a lot more than I expected.

A great variety of queries that power the user interface and general operation of a typical data-driven Java application can be expressed as criteria queries, and they provide advantages in readability, compile-time type checking, and even (surprisingly) compactness. As far as experimental APIs go, I'd call this a winner.

When criteria queries don't quite do the job, you can turn to the full power of HQL, which we'll investigate in the next chapter.



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