Rate this page

Bind a value to a named parameter in a Hibernate query

Tested on

Hibernate (3.6.9)

Objective

To bind a value to a named parameter in a Hibernate query

Background

In HQL (as with SQL) it is considered bad practice to pass arguments into a query by directly inserting the required values as strings. The most important reason for this is to protect against injection attacks (which are possible in HQL, despite the lack of support for comments as such). The solution for both SQL and HQL is the same: use a placeholder within the query string to represent the parameter, then bind the placeholder to the required argument value using a mechanism provided by the query API.

Other benefits of this approach are that it is more robust to non-malicious errors, potentially more efficient, and able to refer to objects which cannot easily be represented as strings.

Scenario

Suppose that you are attempting to refactor a program containing the following function:

public final Page getPageByUrl(String url) throws NoResultException {
  return em.createQuery("FROM Page WHERE url = '" + url + "'", Page.class)
    .getSingleResult();
}

You wish to obtain equivalent functionality without interpolating the URL argument into the query string. The identifier em refers to the relevant EntityManager instance. The class Page is capable of being persisted, and has a property named url of type String.

Method

The desired effect can be achieved by:

  1. replacing the URL literal with a named parameter introduced by a colon, then
  2. binding an argument to the parameter using the setParameter function.

In this instance url would be a reasonable name for the parameter:

public final Page getPageByUrl(String url) throws NoResultException {
  return em.createQuery("FROM Page WHERE url = :url", Page.class)
    .setParameter("url", url)
    .getSingleResult();
}

Note that the name url being used for three different but related purposes within this function:

Alternatives

HQL also supports positional parameters, using the same representation as JDBC (a question mark for each instance). The function used to bind values has the same name (setParameter), but takes an integer as the first argument as opposed to a string. Parameters are numbered from one:

public final Page getPageByUrl(String url) throws NoResultException {
  return em.createQuery("FROM Page WHERE url = ?", Page.class)
    .setParameter(1, url)
    .getSingleResult();
}

Further Reading

Tags: java