Monday, October 19, 2009

Section 8.4. Applying Criteria to Associations








8.4. Applying Criteria to Associations


So far we've been looking at the properties of a single class in forming our criteria. Of course, in our real
systems, we've got a rich set of associations between objects, and
sometimes the details we want to use to filter our results come from these
associations. Fortunately, the criteria query API
provides a straightforward way of performing such searches.



8.4.1. How do I do that?


Let's suppose we're interested in finding all the tracks
associated with particular artists. We'd want our criteria to look at
the values contained in each Track's artists property, which is
a collection of associations to Artist objects.
Just to make it a bit more fun, let's say we want to be able to find
tracks associated with artists whose name property matches a particular substring
pattern.


Let's add a new method to QueryTest.java to implement this. Add the
method shown in Example 8-16 after the end of the
tracksNoLongerThan⁠⁠(⁠ ⁠) method.


Example 8-16. Filtering tracks based on their artist associations



/**
* Retrieve any tracks associated with artists whose name matches a SQL
* string pattern.
*
* @param namePattern the pattern which an artist's name must match
* @param session the Hibernate session that can retrieve data.
* @return a list of {@link Track}s meeting the artist name restriction.
*/
public static List tracksWithArtistLike(String namePattern, Session session)
{
Criteria criteria = session.createCriteria(Track.class);
Criteria artistCriteria = criteria.createCriteria("artists");
artistCriteria.add(Restrictions.like("name", namePattern));
artistCriteria.addOrder(Order.asc("name").ignoreCase());
return criteria.list();
}






To see all this in action, we need to make one more change. Modify
the main⁠⁠(⁠ ⁠) method so that it invokes this
new query, as shown in Example 8-17.


Example 8-17. Calling the new track artist name query



...
// Ask for a session using the JDBC information we've configured
Session session = sessionFactory.openSession();
try {
// Print tracks associated with an artist whose name ends with "n"
List tracks = tracksWithArtistLike("%n", session);
for (ListIterator iter = tracks.listIterator() ;
...




Running ant qtest now gives the
results shown in Example 8-18.


Example 8-18. Tracks associated with an artist whose name ends with the
letter "n"



qtest:
[java] Track: "The World '99" (Pulp Victim, Ferry Corsten) 00:07:05, from D
igital Audio Stream
[java] Track: "Adagio for Strings (Ferry Corsten Remix)" (William Orbit, Sa
muel Barber, Ferry Corsten) 00:06:35, from Compact Disc
[java] Track: "Gravity's Angel" (Laurie Anderson) 00:06:06, from Compact Di
sc





8.4.2. What just happened?


NOTE


You can also create aliases for the associations with which
you're working, and use those aliases in expressions. This starts
getting complex but it's useful. Explore it someday.



If you look at the lists of artists for each of the three tracks
that were found, you'll see that at least one of them has a name ending
in "n" as we requested (they're in bold type for easier recognition in
this printing). Also notice that we have access to all the artists
associated with each track, not just the ones that matched the name criterion. This is what you'd expect and
want, given that we've retrieved the actual Track
entities. You can run criteria queries in a different mode, by
calling setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP), which causes it to
return a list of hierarchical Maps in which the
criteria at each level have filtered the results. This goes beyond the
scope of this book, but there are some examples of it in the reference
and API documentation.



If the table from which you're fetching objects might contain
duplicate entries, you can achieve the equivalent of
SQL's "select distinct" by calling setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY) on your criteria.












No comments:

Post a Comment