Chapter 6. DAOs and Querying

If the domain model serves as the persistence tier's foundation, then the DAO layer might be considered the engine. As you've learned in previous chapters, the DAO pattern is intended to abstract lower-level persistence functionality, including creating, reading, updating, and deleting entities. But a DAO typically provides more than basic CRUD functionality.

Specialized queries that reflect the core entity-access capability of an application are usually baked into a DAO layer. For example, since our gallery application requires that end users be able to view a series of images within a particular category, the ability to query and load the relevant ArtEntity domain objects by a specified Category should be provided by a DAO class. In other words, you can think of an application's DAO classes as the building blocks utilized by the service layer to provide the necessary persistence-related functionality for the application. We will discuss the service layer in the next chapter, but it is helpful to keep in mind that the service layer typically encapsulates an application's business logic, relying on the DAO layer to get the persistence dirty work done.

One of the reasons that the DAO pattern is considered a best practice is that it helps to abstract the persistence implementation details (and technology) from the DAO interface. This allows application developers to settle on the methods and features of a particular DAO, extracting these specifics into the interface. The DAO interface then becomes the integration hub between the actual persistence implementation and the service layer—the contact for lower-level persistence functionality. This is another area where Spring can help to decouple these components.

In this chapter, we will build some of the DAO classes for our art gallery application and look at how to use the various querying mechanisms afforded to us by Hibernate and JPA, such as Hibernate Query Language (HQL), Java Persistence Query Language (JPQL), and the Criteria API.

A Basic Hibernate DAO Implementation

To begin our first DAO implementation, we will turn to Spring's HibernateTemplate. This support class leverages the Template design pattern, an approach used numerous times throughout the framework.

Note

Although it is one of the more commonly used techniques, building DAO classes on the HibernateTemplate is not the only approach to take. We will examine a few alternative solutions later in this chapter. Since HibernateTemplate has been around for many years, you are bound to run into some legacy code that uses it, even if you opt for an alternative strategy.

The HibernateTemplate handles most of the boilerplate operations required by Hibernate, delegating to your code for the important parts. When working with Hibernate (or any persistence framework), a fair amount of resource management is required to get everything working reliably. For instance, before performing a persistence-related operation, some setup is required. You need to open a database connection and get a Hibernate session. You also may set up transactional requirements or check if there is an existing transaction that you should take part in. Finally, after an operation completes, some cleanup is required, ensuring that the session is closed and transactions are properly committed or rolled back.

The HibernateTemplate takes care of these arduous steps. It also catches any exceptions that may occur and translates them into Spring's own data-access exceptions. This conversion allows you to work with a consistent exception hierarchy that is not tied to a specific persistence framework, so you can easily switch between disparate persistence technologies without needing to change the exception handling throughout your code.

Note

Spring's exception hierarchy does not use checked exceptions, meaning you aren't required to catch any of these exceptions. When it comes to database operations, unchecked exceptions are far more pragmatic. If something goes awry when you are trying to write to the database, chances are there's nothing your application can do to recover. So what is the point of handling this exception if you can't do much about it anyway?

Building a DAO

We'll start with the CategoryDAO implementation for our gallery application. ArtEntity domain classes can be organized into one or more categories. This feature allows end-users to browse for photos and artwork by categories. We define the CategoryDao interface as follows:

public interface CategoryDao {

  public List<Category> getCategories() throws DataAccessException;

  public Category getCategory(Long catId) throws DataAccessException;

  public List<ArtEntity> getArtworkInCategory(Long catId)
      throws DataAccessException;

  public void saveCategory(Category category) throws DataAccessException;

}

Note

Although we introduced our GenericDao approach earlier in this book, we are going to take a step back and examine rolling a DAO from scratch. Typically, we would extend from our GenericDao implementation and define those additional methods not provided by the GenericDao base class.

With these methods, we can load an individual category, find all the categories, and access artwork within a particular category. The CategoryDao enables us to save new instances of Category objects as well. Of course, our application might also define a few additional Category-related persistence methods, but this interface is sufficient for illustrative purposes.

Using Spring's Hibernate Support Classes

Spring excels at reducing the amount of code you need to write in order to get something to work. When it comes to building Hibernate DAO classes, you have several options. One of the more common solutions is to extend Spring's HibernateDaoSupport class. This abstract class requires that you pass in a Hibernate SessionFactory via the setSessionFactory(SessionFactory sessionFactory) setter method. You should, of course, configure your SessionFactory in Spring so that it can be easily injected via configuration. We will demonstrate this process shortly.

When a valid SessionFactory is injected into a class that extends HibernateDaoSupport, a HibernateTemplate instance is automatically created for you, using the SessionFactory reference that was passed in. The HibernateTemplate works in a similar fashion to the Spring Framework's other template abstractions, such as the JDBCTemplate and TransactionTemplate. Following the Template design pattern, this class handles all the heavy lifting required by Hibernate so that you can focus on the persistence logic. The result is cleaner code that usually reflects very little other than the Hibernate persistence operations you are implementing.

Extending the HibernateDaoSupport class is ideal for reducing code, since it automatically defines a setter for your Hibernate SessionFactory and handles the creation of a HibernateTemplate. However, if your DAO needs to extend from a different base class, you won't be able to extend HibernateDaoSupport as well. Of course, flexibility and decoupling are key Spring philosophies, and therefore you are rarely required to extend from framework classes (although this is sometimes preferred). Instead, you can simply create your HibernateTemplate directly:

@Repository("categoryDao")
public class CategoryDaoImpl implements CategoryDao {

    private SessionFactory sessionFactory;
    private HibernateTemplate hibernateTemplate;

    @Autowired
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
        this.hibernateTemplate = new HibernateTemplate(sessionFactory);
    }

}

This approach requires a little more plumbing, but you are now free from extending any framework-specific classes. Notice that we created our HibernateTemplate within our setSessionFactory(SessionFactory sf) setter method. This way, when Spring injects the Hibernate SessionFactory, the HibernateTemplate will be automatically created. We applied the @Repository annotation to help Spring find our DAO via component scanning, and used the @Autowired annotation to inject the SessionFactory.

In the above snippet, we are using the @Autowired annotation to automatically inject a bean of type DataSource. Provided we have only a single bean of type DataSource, this example will work fine. If your application requires multiple datasources, you will need to ensure that you remove any potential for ambiguity. As discussed in Chapter 2, you can use the @Qualifier annotation to provide Spring with the necessary hints so that it is able to distinguish among your datasources.

The choice over which configuration approach to use largely depends on your coding style. In the preceding example, we use the @Repository annotation, indicating that we are configuring a class with persistence-related functionality. This annotation is used by Spring's component-scanning facility, which we introduced in Chapter 3. With component scanning, Spring searches a specified package structure to find those classes annotated as components so that they can be managed by Spring and play a role in dependency injection.

Spring defines three core stereotype annotations, each representing a layer within a typical application:

  • @Repository is used to delineate those classes that provide data repository functionality. In this case, it is our DAO implementation, as it serves the purpose of abstracting all data-access functionality that relates to the Category domain object.

  • @Controller is used to delineate controller classes, which are used in the web layer to handle requests.

  • @Service defines a service facade. Typically, the service layer wraps the DAO layer, providing a coherent, transactional service that often serves as the business logic for an application. The service layer is often called a façade, since it serves as an abstraction over the data-access code, hiding the lower-level implementation details and providing a business-specific API. We will discuss the service layer in more detail in Chapter 8.

These three annotations logically extend from the @Component annotation, which defines any bean intended to be managed by the Spring container. In fact, we could just as easily have used @Component instead of @Repository in our example, but we would lose the intention of our class as a DAO. In other words, we use the @Repository annotation to clue Spring in to the fact that our class is a DAO.

To ensure that our CategoryDao class will be configured into our Spring ApplicationContext, we will need to add a component-scanning bean like the following to our Spring XML configuration:

<context:component-scan base-package=
        "com.prospringhibernate.gallery.dao.hibernate">
    <context:include-filter type="annotation" expression=
        "org.springframework.stereotype.Repository"/>
</context:component-scan>

This XML snippet tells Spring to look for classes annotated with @Repository within the com.prospringhibernate.gallery.dao.hibernate package. Eventually, we will have multiple DAO implementations in this package, all configured in a similar fashion.

Enabling Query Caching with the HibernateTemplate

The HibernateTemplate includes two methods needed to facilitate query caching. Using a query cache with Hibernate can provide a significant performance boost by minimizing the number of trips to the database. However, you should verify the performance benefits of query caching carefully, as sometimes query caching can actually have a detrimental effect on application performance. We discuss this in more detail in Chapter 9.

There are several different strategies for enabling query caching. One approach is to configure a HibernateTemplate directly in your Spring configuration. This way, you can externalize and centralize query cache specifics:

<bean id="hibernateTemplate"
      class="org.springframework.orm.hibernate3.HibernateTemplate">
    <property name="sessionFactory" ref="sessionFactory"/>
    <property name="queryCacheRegion" value="querycache_artwork"/>
    <property name="cacheQueries" value="true"/>
</bean>

Note

You must first enable query caching globally by adding the following hibernate property to the hibernateProperties map when creating your SessionFactory:

<prop key="hibernate.cache.use_query_cache">true</prop>

You can then inject this preconfigured HibernateTemplate directly into your DAO implementation. If your DAO extends from the HibernateDaoSupport class, it will use the SessionFactory applied to your Spring-configured HibernateTemplate automatically. Using this strategy, you can ensure that query caching is enabled for all operations that make use of the HibernateTemplate. The downside to this technique is that you are using a centrally configured HibernateTemplate, which makes it difficult to apply customizations for specific DAOs that rely upon it. An alternative approach is to configure query caching details in code through extending HibernateTemplate or setting the query cache specifics directly.

Going Template-less

When you use Spring's template abstractions, you don't need to worry about handling boilerplate processes and resource management. Most Hibernate operations can be managed through the HibernateTemplate.

When working with Hibernate directly, you normally are required to create a new Hibernate Session from a SessionFactory. For most operations, you also need to be concerned with transactional details, ensuring that transactions are started at the beginning of an operation, and then either committed or rolled back when the operation completes. The HibernateTemplate (along with other Spring Framework classes) will ensure that the Hibernate Session is opened and closed, and that transactional semantics are properly applied. However, using a HibernateTemplate is not the only valid approach, when using Spring and Hibernate together.

Note

You are free to specify transactional requirements all in code. However, doing so can be verbose and error-prone. Instead, we recommend specifying transactional requirements entirely via configuration, separating transactional details from our persistence logic. This is one of the key purposes of the service facade layer.

The introduction of the HibernateTemplate came early in Hibernate's development. Prior to Hibernate 3, Hibernate suffered from "a few architectural flaws." Unlike today's version, earlier versions of Hibernate had a checked exception hierarchy, which required developers to write messy DAO code as a result of attempting to handle Hibernate's exceptions through a series of nested try-catch-finally blocks.

With the release of Hibernate 3.0.1, things became a bit simpler. Hibernate swapped its checked exception hierarchy for unchecked exceptions, removing the requirement for sloppy try-catch blocks. Additionally, Hibernate introduced the concept of a contextual session, which allows Hibernate to associate and synchronize a single session with the current transaction. This is a similar to what Spring provides in its Hibernate support, allowing sessions to automatically participate in transactions.

In its Hibernate 3 support, Spring's LocalSessionFactoryBean classes integrate with Hibernate's contextual session support, creating a proxied Hibernate SessionFactory by default. This proxied version of the SessionFactory enhances its getCurrentSession method, allowing it to be automatically synchronized with Spring's resource management, such as transactional features.

Going with the standard Hibernate APIs rather than utilizing Spring's HibernateTemplate might simplify some development, but you lose some benefits. Spring's template support provides a level of consistency across various persistence technologies; for example, Spring's JDBCTemplate works in a similar fashion to the HibernateTemplate or the JPATemplate.

Additionally, Spring's template support automatically translates a particular persistence framework's exceptions into the appropriate exception from Spring's DataException hierarchy, further decoupling your code from a particular technology. But there is a way to achieve this without using the HibernateTemplate. If you add a BeanFactory PostProcessor, Spring can detect any DAO classes annotated with the @Repository annotation and automatically translate Hibernate exceptions into the Spring generic DataAccessException hierarchy. To make this work, simply add the following bean to your Spring configuration:

<bean class="org.springframework.dao.annotation.
Going Template-less
PersistenceExceptionTranslationPostProcessor"/>

Then ensure your DAO classes are properly annotated with @Repository, and you will be able to use the Hibernate API directly in your DAO implementation, rather than relying on HibernateTemplate. You can instead just define getters and setters for the Hibernate SessionFactory, allowing the AnnotationSessionFactoryBean to inject a proxied SessionFactory into your class. Then you can implement your DAO methods by accessing the Hibernate session via the following:

this.getSessionFactory().getCurrentSession()

A more complete implementation might look like this:

@Repository("categoryDao")
public class CategoryDaoHibernate implements CategoryDao {

    private SessionFactory sessionFactory;

    public SessionFactory getSessionFactory() {
        return this.sessionFactory;
    }
@Autowired
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    @SuppressWarnings("unchecked")
    public List<Category> getCategories() throws DataAccessException {
        return this.getSessionFactory().getCurrentSession().createQuery(
            "select categories from Category categories"
        ).list();
    }

    . . .

}

This example is a bit contrived, but it should provide you with a clearer sense of how you can leverage the Hibernate API directly while still taking advantage of Spring's powerful resource-management features. Which approach you take depends on your preferences and specific requirements. For example, if your organization uses other persistence technologies, such as JDBC or iBatis, then using HibernateTemplate may still be a good idea, since it provides greater consistency within the organization and perhaps the code base. Additionally, HibernateTemplate can also provide a few shortcuts that are not available with the direct Hibernate APIs, such as setting default behavior (for example, to activate cache settings) across an entire DAO.

Although we focus on the usage of Hibernate a bit more than JPA in this chapter, keep in mind that the two approaches are quite similar—especially when it comes to HQL and JPQL syntax. For this reason, we aren't going to examine every example from both a Hibernate and JPA perspective. However, to give you a clearer sense of how we might set up a JPA-based DAO, let's look at a short example:

@Repository("categoryDao")
public class CategoryDaoHibernate implements CategoryDao {

    private EntityManager entityManager;

    @PersistenceContext
    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    @SuppressWarnings("unchecked")
    public List<Category> getCategories() throws DataAccessException {
        return this.entityManager.createQuery(
        "select categories from Category categories"
        ).getResultList();
    }

    . . .

}

Notice that the JPA version of our simple DAO example is quite similar, with a few syntax differences. The most significant variation is the use of @PersistenceContext to inject our JPA EntityManager. This annotation depends on the inclusion of a BeanPostProcessor in our Spring configuration, which will help to perform the standard JPA configuration, using the persistence.xml file. You can add this BeanPostProcessor by adding the following to your Spring configuration:

<bean class="org.springframework.orm.jpa.support.
Going Template-less
PersistenceAnnotationBeanPostProcessor" />

Throughout this book, we will include examples that use the Hibernate APIs, Core JPA and HibernateTemplate or JPATemplate to demonstrate a broader range of implementations.

Querying in Hibernate

Now that we've examined some approaches for implementing our DAO and have taken care of all the wiring details, let's move on to the actual implementation. We will consider the following as the first version of our CategoryDao implementation:

@Repository("categoryDao")
public class CategoryDaoImpl extends HibernateDaoSupport 
Querying in Hibernate
implements CategoryDao { public List<Category> getCategories() throws DataAccessException { return this.getHibernateTemplate().find( "select categories from Category categories" ); } public Category getCategory(Long catId) throws DataAccessException { return (Category) this.getHibernateTemplate() .load(Category.class, catId); } public List<ArtEntity> getArtworkInCategory(Long catId) throws DataAccessException { return this.getHibernateTemplate().findByNamedParam( "select art from Category cat " + "join cat.artEntities art "+ "where cat.id = :catId ", "catId", catId ); } public void saveCategory(Category category) throws DataAccessException { this.getHibernateTemplate().saveOrUpdate(category); } }

If you're not attempting to access a single entity, you will likely need to execute a query using either HQL or the Hibernate Criteria API. Here, we will look at how to use HQL to meet our persistence requirements for the CategoryDAO. We will start with the fundamentals and gradually work our way up to the more complex querying approaches.

Loading an Entity

One of the most basic operations you can perform in Hibernate is loading an entity by its identifier. Hibernate provides two primary means of accessing an entity from the database: load and get. Although these two methods do the same thing, there are slight differences in how they behave.

For example, to load a Category instance from the database, we could use the getCategory method defined in our sample implementation. Alternatively, we could also use the Hibernate Core APIs directly:

public Category getCategory(Long catId) throws DataAccessException {
    return (Category) this.getSessionFactory().getCurrentSession()
Loading an Entity
.load(Category.class, catId); }

As you can see in this example, the load method takes the entity class, followed by the entity identifier.

We could instead implement the getCategory method using Session.get:

public Category getCategory(Long catId) throws DataAccessException {
    return (Category) this.getSessionFactory().getCurrentSession()
Loading an Entity
.get(Category.class, catId); }

The two methods seem nearly identical, but have subtle differences. Session.load will throw an exception if there is no row in the database that matches the specified identifier. However, when using Spring's persistence support, Hibernate exceptions should be automatically converted to Spring's consistent DataAccessException hierarchy. Session.get will return null if the entity doesn't exist. However, load provides performance benefits that get does not provide. For instance, load can return a proxy rather than immediately hitting the database, which can allow multiple load operations to be batched.

Querying for a Particular Type

A common HQL operation is to find a set of entities of a given type that match a specific condition. HQL is fairly close to SQL semantically, except that it offers an object-oriented perspective, compared with SQL's more table-based approach. Here's a very basic query:

select categories from Category categories

In this example, we are using the select keyword to indicate which items to return. We could instead return a list of strings representing the category names of all the Category entities, as follows:

select categories.name from Category categories

In these examples, we use the from keyword to indicate which entity types to query against. We then alias Category to categories, allowing us to use this alias within the select clause to further reference the Category entity in the query.

These two queries will attempt to work with all the rows in the Category table. To filter our results, we need to add a condition to our query. Let's look at conditional queries next.

Using Named Parameters

Let's jump ahead to the finder method that gets all ArtEntity instances within a particular Category:

public List<ArtEntity> getArtworkInCategory(Long catId)
                                             throws DataAccessException {
    return this.getHibernateTemplate().findByNamedParam(
        "select art from Category cat " +
        "join cat.artEntities art " +
        "where cat.id = :catId ",
        "catId", catId
    );
}

This method uses a more complex HQL query that joins Category with ArtEntity, specifying a where condition with a parameterized CategoryId. Joins in HQL allow you to query across multiple entities. In this example, we are referencing the ArtEntity domain class through the artEntities property of the Category entity.

In Hibernate, it is possible to join two entity types explicitly or implicitly. Implicit uses of join don't actually use the join keyword, but instead navigate across object properties and associations as part of a query. For example, we could implicitly join Category and ArtEntity domain objects using the following query:

from ArtEntity artEntities where artEntities.category.id = :catId

Here, we navigate across associations within the where condition. This returns the same result but through a different approach.

For this method, we are using HibernateTemplate's findByNamedParam method. This method takes three parameters: the HQL query, the HQL parameter name, and the parameter itself. We recommend using named parameters instead of positional parameters to make your code significantly clearer and less brittle. Positional parameters rely on the order in which the parameters are passed in, which is ambiguous and more prone to errors.

Notice that our HQL query specifies the condition where cat.id = :catId. The :catId is Hibernate's way of defining a named parameter in a query. This name can then be referenced as the parameter name to the HibernateTemplate's findByNamedParam method.

In the preceding example, we have only a single parameter, but this is not typically the case. When you require more than a single HQL parameter, you can use the overloaded version of findByNamedParam that takes a String array (as the second parameter) to define the parameter names you are passing into your finder method, and an Object array for the actual parameter values. This more flexible version works about the same as the preceding example, except the second and third parameters both take arrays instead of a String and an Object, respectively. For instance, let's take a look at our authenticatePerson method in the PersonDaoImpl class:

public Person authenticatePerson(String username, String password)
                   throws DataAccessException, AuthenticationException {

    List<Person> validUsers = this.getHibernateTemplate().findByNamedParam(
        "select people from Person people where" +
        "people.username = :username " +
        "and people.password = :password",
         new String[] {"username", "password"},
         new String[] {username, password }
    );

    if (validUsers == null || validUsers.size() <= 0) {
        throw new AuthenticationException("No users found");
    } else {
        return validUsers.get(0);
    }
}

In this example, we are passing two conditions to our HQL query: username and password. The second argument contains a String array of HQL parameter names, and the third method argument takes a String array of values. The HibernateTemplate also offers overloaded alternatives in which you can specify an Object or Object array for parameter values, allowing you to use any Java type as a parameter value in an HQL query.

Querying Using Core Hibernate

In the previous section, we discussed how to execute HQL queries using the HibernateTemplate. Although this approach works reasonably well, you probably noticed that things can get somewhat confusing when specifying multiple named parameters. As we discussed earlier, HibernateTemplate isn't always the most ideal way to implement your DAOs. Let's now look at how the authenticatePerson method is implemented using the Hibernate Core APIs:

public Person authenticatePerson(String username, String password)
                      throws DataAccessException, AuthenticationException {

    Person validUser =
        (Person) this.getSessionFactory().getCurrentSession().createQuery(
            "select people from Person people where" +
            "people.username = :username " +
            "and people.password = :password")
            .setString("username", username)
            .setString("password", password)
            .uniqueResult()
        );

    if (validUser == null) {
            throw new AuthenticationException("No users found");
} else {
        return validUser;
    }
}

As you can see, this form is a bit clearer and more concise than the HibernateTemplate version. The Hibernate Core APIs provide an easy way to set named parameters, one at a time, using a chained syntax (meaning that each Query method returns the Query instance, allowing you to invoke multiple methods in a row). You can also return a list or call uniqueResult(), which assumes that the query will return only a single item, allowing you to return this item directly. If you want your query to return a list, you can invoke .list() instead of .uniqueResult().

Hibernate also provides an .iterate() method on the Query class, which can be useful if there is a decent chance that most of the entities returned by the query are stored in cache. The .iterate() method will return only the identifiers of each entity, rather than the entire entity itself. Assuming the IDs are cached, this will result in a more performant operation.

Using Named Queries

Even though the Hibernate Core APIs help to simplify our implementation, the method still seems a bit complex, due primarily to the length of the query itself, which we break into chunks for readability. We also rely on String concatenation, which incurs a slight performance hit.

One approach to making HQL-based methods clearer is to use a named query. Named queries allow you to externalize queries from the code itself. This can improve code clarity, while centralizing queries either outside the code entirely or grouped within a particular part of the file.

If you use Hibernate XML mapping files, you can define named queries directly within those files. This makes it possible to alter queries without needing to recompile your Java code. Alternatively, you can define named queries within your code by using the @NamedQuery annotation.

Once you have specified your named queries, you can easily access them using the following syntax (assuming the query is named my.named.query.name):

Query query = this.getSessionFactory().getSession().getNamedQuery("my.named.query.name");

Once you have a Query reference, you can work with it in exactly the same way as if you had created the query directly in code.

We recommend that you avoid placing HQL queries directly within the DAO code. Instead, use Hibernate's named query feature. This allows you to centralize your HQL queries within Hibernate mapping files or within domain class files using the @NamedQuery annotation. As we mentioned earlier, keeping named queries within XML mapping files also lets you tweak your queries without needing to recompile classes, which can come in handy when debugging a crisis in a development or Staging environment.

Working with Polymorphic Queries

In Chapter 5, you learned about the different strategies for mapping a Java class hierarchy. You can see some of the benefits of Hibernate's support for polymorphism when you consider the querying features.

For instance, in Chapter 5, we defined a class hierarchy intended to encapsulate the different image resolutions persisted within the gallery application: ArtData, ArtData_Gallery, ArtData_Thumbnail, and ArtData_Storage. In this hierarchy, the latter three classes extend from the ArtData base class. Now suppose that we want to find all instances that extend from ArtData. We can accomplish this with the following query:

Select artData from ArtData artData

This will return all instances of ArtData, including entities such as ArtData_Gallery and ArtData_Thumbnail, which extend from the ArtData parent class. Hibernate's support for polymorphism is extremely powerful, as it allows us to restrict or broaden a query across a class hierarchy. In fact, we could query for all instances of every domain object in our application by running the query:

From Object

The above query would load our entire database, since every domain object implicitly inherits from Object. Obviously, we strongly discourage you from trying this in a production application!

Persisting Data with Hibernate

Now that we've discussed a few options for defining finder methods using HibernateTemplate and the Hibernate Core APIs, how do we actually persist data?

Saving and Updating Data

Our CategoryDaoImpl class defines a save method for the Category instance as follows:

public void saveCategory(Category category) throws DataAccessException {
    this.getHibernateTemplate().saveOrUpdate(category);
}

Using HibernateTemplate's saveOrUpdate is similar to calling Session.saveOrUpdate(Object) using the Hibernate Core APIs. Other saving options are available in the HibernateTemplate, such as merge, save, and update, if you want more specific kinds of persisting behavior.

It is even possible to perform batch operations using Hibernate, updating multiple objects using a where condition to determine which entities should be updated. You can also update a collection of domain objects by iterating through the entities and calling saveOrUpdate on each entity. We will discuss performance optimization strategies for saving objects in Chapter 9.

Handling Binary Data

Our CategoryDao is fairly straightforward, as it needs to manipulate only simple String fields. However, since we are building a gallery application, we will need to handle large data types in order to manage the data used to represent imagery. We could choose to store image data on the file system, storing only path references to the location where images are stored. However, we've found that it is often more flexible to persist everything in the database, ensuring your application data is completely centralized. This also helps to reduce coupling to the file system, and can make it easier to back up and migrate data.

In the database world, large objects (LOBs) are used to represent large binary fields. Typically, LOBs or BLOBs represent binary data while CLOBs are used to represent exceedingly large (typically more than 4,000 characters) character data. The process for working with these field types in Spring is similar. First, we need to create a DefaultLobHandler reference to be used within our inserts and queries. This Spring abstraction is intended to simplify the manipulation of LOB fields. We can create our DefaultLobHandler by adding the following snippet to our Spring configuration:

<bean id="defaultLobHandler"
      class="org.springframework.jdbc.support.lob.DefaultLobHandler" />

Next, we need to inject our defaultLobHandler reference into our DAO layer. We don't need LOB support in our CategoryDao implementation, and we haven't defined our ArtEntityDao just yet. To conserve space, we won't get into the details of our ArtEntityDao here. Just keep in mind that this interface will handle persistence operations for the ArtEntity domain object (which represents a particular image within our gallery application). Additionally, remember that LOB fields within the domain model should be annotated with @Lob, to indicate that the property should be mapped to a database Lob type.

Let's begin stubbing out our HibernateArtEntityDao implementation:

public class HibernateArtEntityDao implements ArtEntityDao {
    private HibernateTemplate template;
    private LobHandler defaultLobHandler;
    // getters and setters omitted
}

We will need to ensure our LobHandler reference is injected into our HibernateArtEntityDao class.

Next, let's define a saveArtEntity method that takes an ArtEntity parameter, which encapsuates information about our image as well as the image data itself. (Again, keep in mind that this is a simplification of our actual ArtEntityDao interface and domain entity.) Our saveArtEntity method might look like the following:

public void saveArtEntity(ArtEntity artEntity) throws DataAccessException {
    this.getHibernateTemplate().saveOrUpdate(artEntity);
}

Understanding the Benefits of the Criteria API

Although HQL and JPQL are effective and concise strategies for expressing a query, they both suffer from a few limitations. First, because these query languages are articulated as plain text, they are prone to errors which are unable to be caught or verified by the compiler. Methods containing significant errors in the HQL or JPQL queries will compile perfectly, only to throw exceptions at runtime — or perform in unexpected ways.

HQL and JPQL are also not conducive to expressing dynamic queries, in which the attributes of the query are not fully known until runtime. For instance, if we would like our users to be able to search for images by specifying any number of tags, it would be difficult to represent this sort of query using HQL or JPQL. To accomplish this, we might try dynamically generating a JPQL query string by concatenating the conditions of each tag parameter. Clearly, this is a fragile and awkward solution to this problem.

To address these limitations, Hibernate offers the Criteria API. Until recently, JPA did not include a Criteria API, forcing developers that needed this type of functionality to go outside of the JPA standard. However, with the release of JPA 2.0, a standards-based Criteria API is now available.

Using the JPA 2.0 Criteria API

We've focused more on Hibernate-specific querying, so let's examine the new JPA 2.0 Criteria API. To illustrate the Criteria API, we will define a new DAO method for our CategoryDao interface:

public List<ArtEntity> getArtEntitiesByTitle(String title);

This method will return all those ArtEntity instances that match the specified title. Obviously, we could express this query using JPQL, however the Criteria API offers some advantages. One of the primary benefits is that we can leverage compile-time checking to ensure that our query is valid and fits within the constraints of our domain model. Later in this section, we will also examine some other advantages of the Criteria API, such as applying dynamic constraints on our query, including pagination, filtering, and ordering details.

First, let's take a look at our query:

public List<ArtEntity> getArtEntitiesByTitle(String title) {
    CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
    CriteriaQuery<ArtEntity> criteriaQuery =
        criteriaBuilder.createQuery(ArtEntity.class);
    Root<ArtEntity> root = criteriaQuery.from(ArtEntity.class);
    Path<String> path = root.<String>get("title");
    criteriaQuery.where(criteriaBuilder.equal(path, title));
    return entityManager.createQuery(criteriaQuery).getResultList();
}

If you consider the structure of a JPQL query, then you should be able to infer what the above method is doing. The first line gets a reference to a CriteriaBuilder. The CriteriaBuilder class is necessary for generating important aspects of our Criteria query, as we will see shortly. The next line then uses our CriteriaBuilder reference to create a CriteriaQuery instance. Notice that we pass ArtEntity.class as the single parameter to the createQuery method. We are essentially requesting that we would like a generically typed CriteriaQuery instance, using our ArtEntity type. Our intention in doing this is to specify that we want our query to return results of type ArtEntity. This doesn't necessarily imply that we are querying against an ArtEntity instance. In fact, we could specify a type of Long.class to the createQuery method, to indicate that our query should return a Long, which is typical when performing projection or aggregate queries.

Now that we have our CriteriaQuery instance, we need to declare what type we intend to query against. We call the from method on our CriteriaQuery instance, specifying a parameter of ArtEntity. This line of code in our example is similar to a JPQL clause that reads: "from ArtEntity". In other words, we are expressing our intention to query against the ArtEntity type. We are returned a Root instance as a result of this method call, which is generically typed to our ArtEntity instance. The Root instance can now be used as a means for referencing properties on the ArtEntity class that we wish to use as conditions in our query.

The next line in our method uses our Root instance to access the title field on our ArtEntity domain class, by calling the get method on the Root instance and specifying the string "title" (which is the appropriate property name on the ArtEntity class). This returns a Path instance, which we can use to represent the title property, in order to express a condition in our query. To express this condition, we call the where method on our CriteriaQuery instance. Notice that as a parameter to the where method, we have used a nested method call of criteriaBuilder.equal(path, title). We use the criteriaBuilder as a factory to construct the equal condition, which returns a Predicate instance. Predicates represent encapsulated logic that will return either true or false, and are used as building blocks in the Criteria API to form complex queries. In our case, we have created a Predicate to represent the comparison logic between the Path instance (which represents our ArtEntity.title field) and the String title parameter, that was passed in to this method.

Now that we've articulated the requirements and conditions for our CriteriaQuery, we need to actually execute our query so that we can access the results. This part of the method works in a similar fashion to executing a JPQL query. We invoke createQuery on our EntityManager reference, passing in our CriteriaQuery instance. The createQuery method will actually return a TypedQuery instance that is generically typed to our ArtEntity domain class. However, to keep our method streamlined, we call getResultList() on the method chain to directly return a List of ArtEntity instances that match our query's conditions.

You're probably thinking that the above example required quite a bit of work to define a query that might be defined in JPQL as:

public List<ArtEntity> getArtEntitiesByTitle(String title) {
    Query query = this.entityManager.createQuery(
        "select art from ArtEntity where art.title = :title "
    );
    query.setParameter("title", title);
    return query.getResultList();

}

It's true that the JPQL version is a bit more concise. However, what about our earlier concerns about a lack of compile-time checking on the validity of our query? With the Criteria API approach, we benefit from some assurance that the syntax of our query is verifiable, whereas in JPQL we won't be aware of issues until runtime. However, in our Criteria API example, we are actually short-changing ourselves a bit. Remember that in order to represent the ArtEntity.title field as a Path reference, we used the following code:

Path<String> path = root.<String>get("title");

This line is intuitive, but we are still opening ourselves up to the potential for error since we could misspell our title field, or specify a domain class property that simply doesn't exist. Additionally, when we get into more complex queries, such as those involving associations, we could lose track of the correct field type or plurality.

To address this problem, the JPA 2.0 Criteria API provides a MetaModel, which can be used to describe the metadata related to your domain model. While it is possible to manually define your own MetaModel, in order to mirror the structure of each of your domain classes, the easier bet is to use the annotation processing feature of Java 1.6. Hibernate offers the hibernate-jpamodelgen jar, which can be used to analyze your domain model classes and then automatically generate the sourcecode for the MetaModel. The first step in getting this to work is to add the hibernate-jpamodelgen to your Maven pom.xml file as a dependency:

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-jpamodelgen</artifactId>
    <version>1.0.0.Final</version>
</dependency>

Once you've added this dependency, you will be able to have your MetaModel automatically generated and updated whenever your code is compiled. While it is possible to make this process more implicit, we recommend installing a Maven plugin to provide some level of control and configuration. For example, you will probably want to specify where the MetaModel classes should be located. Copy the following plugin configuration into the <plugins> block of your pom.xml:

<plugin>
  <artifactId>maven-compiler-plugin</artifactId>
  <configuration>
    <source>1.6</source>
    <target>1.6</target>
    <compilerArguments>
      <processor>
        org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor
      </processor>
    </compilerArguments>
  </configuration>
</plugin>

<plugin>
  <groupId>org.bsc.maven</groupId>
  <artifactId>maven-processor-plugin</artifactId>
  <executions>
    <execution>
      <id>process</id>
      <goals>
        <goal>process</goal>
      </goals>
      <phase>generate-sources</phase>
      <configuration>
        <!-- source output directory -->
        <outputDirectory>src/main/generated-java</outputDirectory>
      </configuration>
    </execution>
  </executions>
</plugin>

<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>build-helper-maven-plugin</artifactId>
  <version>1.3</version>
  <executions>
    <execution>
      <id>add-source</id>
      <phase>generate-sources</phase>
      <goals>
        <goal>add-source</goal>
      </goals>
      <configuration>
        <sources>
          <source>src/main/generated-java</source>
</sources>
      </configuration>
    </execution>
  </executions>
</plugin>

It may also be necessary to add a <pluginrepositories> block to your pom.xml, if you have trouble automatically installing the above plugins. You can add the following block, to ensure that the necessary plugins can be downloaded:

<pluginRepositories>
  <pluginRepository>
    <id>maven-annotation</id>
    <url>
      http://maven-annotation-plugin.googlecode.com/svn/trunk/mavenrepo/
    </url>
  </pluginRepository>
</pluginRepositories>

Once you've updated your Maven configuration, you should be able to run mvn compile in order to trigger the annotation processing to have your MetaModel generated. The above Maven configuration will generate the MetaModel source to src/main/generated-java, but feel free to update the location to suit your own needs.

Once you have generated your MetaModel, you should be able to find these classes in the appropriate location. The MetaModel classes mirror your own domain model classes, except that an underscore is suffixed to the class name. For instance, our ArtEntity domain class would have a corresponding MetaModel class in the same package structure but with the name ArtEntity_. Let's take a look at what our ArtEntity MetaModel class looks like:

@StaticMetamodel(ArtEntity.class)
public abstract class ArtEntity_ {

    public static volatile SingularAttribute<ArtEntity, String> displayDate;
    public static volatile SingularAttribute<ArtEntity, Integer> width;
    public static volatile SingularAttribute<ArtEntity, Integer> hashCode;
    public static volatile SingularAttribute<ArtEntity, String> caption;
    public static volatile SingularAttribute<ArtEntity, Boolean> 
Using the JPA 2.0 Criteria API
privilegeViewable; public static volatile SingularAttribute<ArtEntity, Boolean>
Using the JPA 2.0 Criteria API
generalViewable; public static volatile SingularAttribute<ArtEntity, Integer> version; public static volatile SingularAttribute<ArtEntity, Long> id; public static volatile SingularAttribute<ArtEntity, String> subTitle; public static volatile SingularAttribute<ArtEntity, String> title; public static volatile SingularAttribute<ArtEntity, Integer> height; public static volatile SingularAttribute<ArtEntity, String> description; public static volatile SingularAttribute<ArtEntity, ArtData_Gallery>
Using the JPA 2.0 Criteria API
galleryPicture;
public static volatile SetAttribute<ArtEntity, Category> categories;
    public static volatile SingularAttribute<ArtEntity, ArtData_Thumbnail> 
Using the JPA 2.0 Criteria API
thumbnailPicture; public static volatile SingularAttribute<ArtEntity, String> media; public static volatile SetAttribute<ArtEntity, Comment> comments; public static volatile SingularAttribute<ArtEntity, ArtData_Storage>
Using the JPA 2.0 Criteria API
storagePicture; public static volatile SingularAttribute<ArtEntity, Date> uploadedDate; }

Notice that the class is quite simple, containing only static volatile properties that correspond to each of our ArtEntity's domain class properties. Since most of the fields in our ArtEntity domain class are scalar properties, they are represented by the SingularAttribute type. However, notice that each MetaModel property is generically typed to indicate both the domain class type (in this case, ArtEntity), as well as the type of the field. This metadata will prove valuable for leveraging compile time checking for all aspects of our Criteria API query — even conditions that reference particular fields.

We should also point out that the comments and categories properties are represented by the SetAttribute type, rather than the SingularAttribute type. Unlike the other fields in the ArtEntity class, the categories and comments properties are collection associations, represented by a java.util.Set.

Now that we have a clearer understanding of the MetaModel and how we can generate it, let's get back to the Criteria API to see how we can use this feature. To better illustrate some other features of the Criteria API, we will examine a different query that will return the count of all ArtEntity instances that fall within a minimum and maximum width and height. Let's take a look at the method:

public Long getCountOfArtEntitiesBySize(MaxMin widthRange,

                                        MaxMin heightRange,
                                        QueryOpts queryOpts) {
    CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
    CriteriaQuery<Long> criteriaQuery =
        criteriaBuilder.createQuery(Long.class);
    Root<ArtEntity> root = criteriaQuery.from(ArtEntity.class);
    Path<Integer> widthPath = root.get(ArtEntity_.width);
    Path<Integer> heightPath = root.get(ArtEntity_.height);
    criteriaQuery.where(criteriaBuilder.and(
        criteriaBuilder.between(widthPath,
                                widthRange.getMin(),
                                widthRange.getMax()),
                                criteriaBuilder.
Using the JPA 2.0 Criteria API
between(heightPath, heightRange.getMin(), heightRange.getMax()))); criteriaQuery.select(criteriaBuilder.count(root)); Long count = entityManager.createQuery(criteriaQuery).getSingleResult(); return count; }

Unlike our previous example, this method returns a Long, since we don't want a list of the ArtEntity instances themselves, but rather a count of how many instances match the specified condition. Notice that we have encapsulated the minimum and maximum values for both the height and width respectively through a custom MaxMin class. For clarity, here is the MaxMin class (which is an inner class of our Dao):

public static class MaxMin {

    private final int max;
    private final int min;

    public MaxMin(int max, int min) {
        this.max = max;
        this.min = min;
    }

    public int getMax() {
        return max;
    }

    public int getMin() {
        return min;
    }

}

Since our query will return a Long value, we invoke criteriaBuilder.createQuery(Long.class) to indicate that the intended return value for our query. We use the criteriaQuery.from() method to indicate that we wish to query against the ArtEntity class, which returns a Root<ArtEntity> instance — just as in the previous example. However, notice that on the next line we call root.get(ArtEntity_.width) to return a Path<Integer> reference, used to indicate the ArtEntity.width field. Unlike in our previous example, we are using our ArtEntity_ MetaModel class to reference attributes of the ArtEntity domain class in a consistent and type-safe way. Notice that we are returned a Path<Integer> instance that reflects the correct generic type. If we simply specified a string value of "width" instead of using the MetaModel, we would not have assurance that our query was accurately reflecting the correct field types.

Next, we use a where condition in which we nest an and expression, into which we further nest two Predicate clauses that articulate the between conditions for our query. We use our CriteriaBuilder as a factory to generate an and Predicate, which takes a variable number of Predicate arguments — all of which must evaluate to true in order for the query condition to be met.

Finally, we invoke criteriaQuery.select(), passing in a nested call of criteriaBuilder.count(root). The inner expression defines an aggregate query of count, specifying our Root instance. This essentially boils down to counting all the ArtEntity instances that match the where condition defined above. The criteriaQuery.select() invocation is used to indicate what is to be selected in the query, which is effectively similar to the select keyword in a JPQL query. The last step is to use the entityManager reference to call createQuery, using our configured CriteriaQuery as a parameter, and then chaining a call to getSingleResult(). Since this query is intended to return the result of an aggregate query, we want to call getSingleResult(), rather than getResultList().

So far, we have seen the benefits of using the Criteria API through the assurances gained by compile-time checking and verification of both the query structure and syntax, as well as the structure of our domain model. Let's look at one more example that touches on some of the benefits of the CriteriaAPI in being able to express queries in which the structure, conditions, and complexity are dynamic in nature. In this example, we define a method that allows us to specify a QueryOpts instance as a parameter, which encapsulates ordering and pagination information, The key differentiator in this (somewhat simplified) example, is that we are able to define a variable-length list of fields we wish to order the results by. However, we could extend this example further, allowing us to also specify dynamic filter criteria as well.

First, let's examine the QueryOpts class, which is simply a wrapper for our pagination and ordering requirements:

public class QueryOpts {
    private int pageNum;
    private int pageSize;
    private List<FieldOrder> orderList;

    public QueryOpts() {

    }

    public QueryOpts(int pageNum, int pageSize, List<FieldOrder> orderList) {
        this.pageNum = pageNum;
        this.pageSize = pageSize;
        this.orderList = orderList;
    }

    public int getPageNum() {
        return pageNum;
    }

    public void setPageNum(int pageNum) {
        this.pageNum = pageNum;
    }

    public int getPageSize() {
        return pageSize;
    }

    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }

    public List<FieldOrder> getOrderList() {
        return orderList;
    }

    public void setOrderList(List<FieldOrder> orderList) {
        this.orderList = orderList;
    }

    public static class FieldOrder {
        private String field;
boolean ascending;

        public FieldOrder() {

        }

        public FieldOrder(String field, boolean ascending) {
            this.field = field;
            this.ascending = ascending;
        }

        public String getField() {
            return field;
        }

        public void setField(String field) {
            this.field = field;
        }

        public boolean isAscending() {
            return ascending;
        }

        public void setAscending(boolean ascending) {
            this.ascending = ascending;
        }
    }

}

Notice that the QueryOpts also contains the static inner-class FieldOrder, which is used to represent a field name and its order direction (i.e. whether it is ascending or descending).

Now that we have a better handle on the QueryOpts class, let's take a look at the method which defines our dynamic query:

public List<ArtEntity> getArtEntitiesByTitle(String title,
                                             QueryOpts queryOpts) {

    CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
    CriteriaQuery<ArtEntity> criteriaQuery =
        criteriaBuilder.createQuery(ArtEntity.class);
    Root<ArtEntity> root = criteriaQuery.from(ArtEntity.class);
    Path<String> path = root.get(ArtEntity_.title);
    criteriaQuery.where(criteriaBuilder.equal(path, title));
    List<Order> orderList = criteriaQuery.getOrderList();
    List<Order> newOrderList = new ArrayList<Order>(orderList);

    for (QueryOpts.FieldOrder fieldOrder : queryOpts.getOrderList()) {
        Order order = null;
        if (fieldOrder.isAscending()) {
            order = criteriaBuilder.asc(root.get(fieldOrder.getField()));
} else {
            order = criteriaBuilder.desc(root.get(fieldOrder.getField()));
        }
        newOrderList.add(order);
    }

    criteriaQuery.orderBy(newOrderList);
    TypedQuery<ArtEntity> query =
        entityManager.createQuery(criteriaQuery);
    query.setFirstResult(queryOpts.getPageNum() * 
Using the JPA 2.0 Criteria API
queryOpts.getPageSize()); query.setMaxResults(queryOpts.getPageSize()); return query.getResultList(); }

Once again, we are querying for ArtEntities that match a specified title. However, this method also takes a second parameter of type QueryOpts. Most of this method is similar to our first Criteria API example. However, notice how we specify the "order by" criteria for our query. We call criteriaQuery.getOrderList() in order to gain access to a List of Order classes. It is important to note that we can't directly change this list, but instead must create a new ArrayList, copying any Order items from the original list into the new list. Next, we use a for loop to iterate through our "order criteria" embedded within the QueryOpts parameter. We perform a few checks to determine whether a particular QueryOpts.FieldOrder item is ascending or descending, and then instantiate the appropriate javax.persistence.criteria.Order instance, using either criteriaBuilder.asc or criteriaBuilder.desc. In either case, notice that we extract a Path instance using root.get(), passing in the field name we wish to order by. Each newly created javax.persistence.criteria.Order instance is added to our newOrderList.

After we have finished looping through our order requirements, we call criteriaQuery.orderBy(), passing in our newOrderList as a parameter. This method call effectively sets our order by criteria, overwriting any previously specified order requirements for this query.

Finally, we use our entityManager reference to create a TypedQuery<ArtEntity> reference, and then use the pagination details embedded in our QueryOpts parameter to set the firstResult and maxResults properties, effectively controlling the range and page-size for our query.

As you can see, the Criteria API is a powerful tool for dynamically expressing queries in an object-oriented way. The Criteria API also supports more advanced features, such as joins and compound predicate expressions, as well as unique capabilities, such as "query by example." For some queries, whether to use JPQL or the Criteria API may be a matter of style. However, we believe it is important to have a thorough understanding of the Criteria API so that you can effectively leverage this feature — especially in those circumstances in which JPQL doesn't offer an elegant or viable solution.

Summary

In this chapter, we introduced some core ORM concepts, and you learned more about how Spring and Hibernate can be used together. We also reviewed some key design patterns that are instrumental to the way in which Spring integrates with many persistence frameworks. Through our gallery application examples, we demonstrated how to implement an effective DAO layer. We examined several options for integrating Hibernate—using the HibernateTemplate as well as using the Hibernate Core APIs.

The DAO pattern is considered a best practice for abstracting persistence-related functionality. Using Hibernate, we demonstrated how to load entities via their identifier, save or update individual entities, and query for domain objects using HQL. We discussed some querying techniques and examined various approaches for performing joins, using both implicit and explicit forms. We also contrasted implementation strategies using Spring's HibernateTemplate and Hibernate Core APIs. Although HibernateTemplate has played a significant role in both Spring and Hibernate's history, its use is becoming less important due to improvements to the Hibernate architecture after version 3.0.1.

This chapter discussed several implementation options for building our gallery application's DAO layer. We built on some of the concepts introduced in the previous chapter, which illustrated mapping strategies for our application's domain model. In the next chapter, we will build on the DAO layer introduced in this chapter, demonstrating how the service layer can be used to define an application's transactional business logic.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.146.37.250