Menu Close
Settings Close

Language and Page Formatting Options

10.4. Querying

If you don't know the identifiers of the objects you are looking for, you need a query. Hibernate supports an easy-to-use but powerful object oriented query language (HQL). For programmatic query creation, Hibernate supports a sophisticated Criteria and Example query feature (QBC and QBE). You may also express your query in the native SQL of your database, with optional support from Hibernate for result set conversion into objects.

10.4.1. Executing queries

HQL and native SQL queries are represented with an instance of org.hibernate.Query. This interface offers methods for parameter binding, result set handling, and for the execution of the actual query. You always obtain a Query using the current Session:
List cats = session.createQuery(
    "from Cat as cat where cat.birthdate < ?")
    .setDate(0, date)

List mothers = session.createQuery(
    "select mother from Cat as cat join cat.mother as mother where = ?")
    .setString(0, name)

List kittens = session.createQuery(
    "from Cat as cat where cat.mother = ?")
    .setEntity(0, pk)

Cat mother = (Cat) session.createQuery(
    "select cat.mother from Cat as cat where cat = ?")
    .setEntity(0, izi)

Query mothersWithKittens = (Cat) session.createQuery(
    "select mother from Cat as mother left join fetch mother.kittens");
Set uniqueMothers = new HashSet(mothersWithKittens.list());
A query is usually executed by invoking list(), the result of the query will be loaded completely into a collection in memory. Entity instances retrieved by a query are in persistent state. The uniqueResult() method offers a shortcut if you know your query will only return a single object. Note that queries that make use of eager fetching of collections usually return duplicates of the root objects (but with their collections initialized). You can filter these duplicates simply through a Set. Iterating results

Occasionally, you might be able to achieve better performance by executing the query using the iterate() method. This will only usually be the case if you expect that the actual entity instances returned by the query will already be in the session or second-level cache. If they are not already cached, iterate() will be slower than list() and might require many database hits for a simple query, usually 1 for the initial select which only returns identifiers, and n additional selects to initialize the actual instances.
// fetch ids
Iterator iter = sess.createQuery("from eg.Qux q order by q.likeliness").iterate();
while ( iter.hasNext() ) {
    Qux qux = (Qux);  // fetch the object
    // something we couldnt express in the query
    if ( qux.calculateComplicatedAlgorithm() ) {
        // delete the current instance
        // dont need to process the rest
} Queries that return tuples

Hibernate queries sometimes return tuples of objects, in which case each tuple is returned as an array:
Iterator kittensAndMothers = sess.createQuery(
            "select kitten, mother from Cat kitten join kitten.mother mother")

while ( kittensAndMothers.hasNext() ) {
    Object[] tuple = (Object[]);
    Cat kitten  = tuple[0];
    Cat mother  = tuple[1];
} Scalar results

Queries may specify a property of a class in the select clause. They may even call SQL aggregate functions. Properties or aggregates are considered "scalar" results (and not entities in persistent state).
Iterator results = sess.createQuery(
        "select cat.color, min(cat.birthdate), count(cat) from Cat cat " +
        "group by cat.color")

while ( results.hasNext() ) {
    Object[] row = (Object[]);
    Color type = (Color) row[0];
    Date oldest = (Date) row[1];
    Integer count = (Integer) row[2];
} Bind parameters

Methods on Query are provided for binding values to named parameters or JDBC-style ? parameters. Contrary to JDBC, Hibernate numbers parameters from zero. Named parameters are identifiers of the form :name in the query string. The advantages of named parameters are:
  • named parameters are insensitive to the order they occur in the query string
  • they may occur multiple times in the same query
  • they are self-documenting
//named parameter (preferred)
Query q = sess.createQuery("from DomesticCat cat where = :name");
q.setString("name", "Fritz");
Iterator cats = q.iterate();
//positional parameter
Query q = sess.createQuery("from DomesticCat cat where = ?");
q.setString(0, "Izi");
Iterator cats = q.iterate();
//named parameter list
List names = new ArrayList();
Query q = sess.createQuery("from DomesticCat cat where in (:namesList)");
q.setParameterList("namesList", names);
List cats = q.list(); Pagination

If you need to specify bounds upon your result set (the maximum number of rows you want to retrieve and / or the first row you want to retrieve) you should use methods of the Query interface:
Query q = sess.createQuery("from DomesticCat cat");
List cats = q.list();
Hibernate knows how to translate this limit query into the native SQL of your DBMS. Scrollable iteration

If your JDBC driver supports scrollable ResultSet s, the Query interface may be used to obtain a ScrollableResults object, which allows flexible navigation of the query results.
Query q = sess.createQuery("select, cat from DomesticCat cat " +
                            "order by");
ScrollableResults cats = q.scroll();
if ( cats.first() ) {

    // find the first name on each page of an alphabetical list of cats by name
    firstNamesOfPages = new ArrayList();
    do {
        String name = cats.getString(0);
    while ( cats.scroll(PAGE_SIZE) );

    // Now get the first page of cats
    pageOfCats = new ArrayList();
    int i=0;
    while( ( PAGE_SIZE > i++ ) && ) pageOfCats.add( cats.get(1) );

Note that an open database connection (and cursor) is required for this functionality, use setMaxResult()/setFirstResult() if you need offline pagination functionality. Externalizing named queries

You may also define named queries in the mapping document. (Remember to use a CDATA section if your query contains characters that could be interpreted as markup.)
<query name="ByNameAndMaximumWeight"><![CDATA[
    from eg.DomesticCat as cat
        where = ?
        and cat.weight > ?
] ]></query>
Parameter binding and executing is done programatically:
Query q = sess.getNamedQuery("ByNameAndMaximumWeight");
q.setString(0, name);
q.setInt(1, minWeight);
List cats = q.list();
Note that the actual program code is independent of the query language that is used, you may also define native SQL queries in metadata, or migrate existing queries to Hibernate by placing them in mapping files.
Also note that a query declaration inside a <hibernate-mapping> element requires a global unique name for the query, while a query declaration inside a <class> element is made unique automatically by prepending the fully qualified name of the class, for example eg.Cat.ByNameAndMaximumWeight.