Hibernate.orgCommunity Documentation

Chapter 9. Criteria Queries

9.1. Typed criteria queries
9.1.1. Selecting an entity
9.1.2. Selecting a value
9.1.3. Selecting multiple values
9.1.4. Selecting a wrapper
9.2. Tuple criteria queries
9.2.1. Accessing tuple elements
9.3. FROM clause
9.3.1. Roots
9.3.2. Joins
9.3.3. Fetches
9.4. Path expressions
9.5. Using parameters

Criteria queries are a programmatic, type-safe way to express a query. They are type-safe in terms of using interfaces and classes to represent various structural parts of a query such as the query itself, or the select clause, or an order-by, etc. They can also be type-safe in terms of referencing attributes as we will see in a bit. Users of the older Hibernate org.hibernate.Criteria query API will recognize the general approach, though we believe the JPA API to be superior as it represents a clean look at the lessons learned from that API.

Criteria queries are essentially an object graph, where each part of the graph represents an increasing (as we navigate down this graph) more atomic part of query. The first step in performing a criteria query is building this graph. The javax.persistence.criteria.CriteriaBuilder interface is the first thing with which you need to become acquainted to begin using criteria queries. Its role is that of a factory for all the individual pieces of the criteria. You obtain a javax.persistence.criteria.CriteriaBuilder instance by calling the getCriteriaBuilder method of the javax.persistence.EntityManagerFactory

CriteriaBuilder builder = entityManagerFactory.getCriteriaBuilder();

The next step is to obtain a javax.persistence.criteria.CriteriaQuery. You do this by one of the 3 methods on javax.persistence.criteria.CriteriaBuilder for this purpose.

CriteriaQuery<T> createQuery(Class<T>)
CriteriaQuery<Tuple> createTupleQuery()
CriteriaQuery<Object> createQuery()

Each serves a different purpose depending on the expected type of the query results.

Note

Chapter 6 Criteria API of the [JPA 2 Specification] already contains a decent amount of reference material pertaining to the various parts of a criteria query. So rather than duplicate all that content here, lets instead look at some of the more widely anticipated usages of the API.

CriteriaQuery<T> createQuery(Class<T>)

The type of the criteria query (aka the <T>) indicates the expected types in the query result. This might be an entity, an Integer, or any other object.

The simplest form of selecting a value is selecting a particular attribute from an entity. But this might also be an aggregation, a mathematical operation, etc.



There are actually a few different ways to select multiple values using criteria queries. We will explore 2 options here, but an alternative recommended approach is to use tuples as described in Section 9.2, “Tuple criteria queries”



Another alternative to Section 9.1.3, “Selecting multiple values” is to instead select an object that will "wrap" the multiple values. Going back to the example query there, rather than returning an array of [Person#id, Person#age] instead declare a class that holds these values and instead return that.


A better approach to Section 9.1.3, “Selecting multiple values” is to either use a wrapper (which we just saw in Section 9.1.4, “Selecting a wrapper”) or using the javax.persistence.Tuple contract.


The javax.persistence.Tuple contract provides 3 basic forms of access to the underlying elements:

typed
<X> X get(TupleElement<X> tupleElement)

This allows typed access to the underlying tuple elements. We see this in Example 9.7, “Selecting a tuple” in the tuple.get( idPath ) and tuple.get( agePath ) calls. Just about everything is a javax.persistence.TupleElement.

positional
Object get(int i)
<X> X get(int i, Class<X> type)

Very similar to what we saw in Example 9.4, “Selecting an array” and Example 9.5, “Selecting an array (2)” in terms of positional access. Only the second form here provides typing, because the user explicitly provides the typing on access. We see this in Example 9.7, “Selecting a tuple” in the tuple.get( 0 ) and tuple.get( 1 ) calls.

aliased
Object get(String alias)
<X> X get(String alias, Class<X> type)

Again, only the second form here provides typing, because the user explicitly provides the typing on access. We have not seen an example of using this, but its trivial. We would simply, for example, have applies an alias to either of the paths like idPath.alias( "id" ) and/or agePath.alias( "age" ) and we could have accessed the individual tuple elements by those specified aliases.

 

A CriteriaQuery object defines a query over one or more entity, embeddable, or basic abstract schema types. The root objects of the query are entities, from which the other types are reached by navigation.

 
 --[JPA 2 Specification, section 6.5.2 Query Roots, pg 262]

Roots define the basis from which all joins, paths and attributes are available in the query. In a criteria query, a root is always an entity. Roots are defined and added to the criteria by the overloaded from methods on javax.persistence.criteria.CriteriaQuery:

<X> Root<X> from(Class<X>)
<X> Root<X> from(EntityType<X>)

Criteria queries may define multiple roots, the effect of which is to create a cartesian product between the newly added root and the others. Here is an example matching all single men and all single women:

CriteriaQuery query = builder.createQuery();

Root<Person> men = query.from( Person.class );
Root<Person> women = query.from( Person.class );
Predicate menRestriction = builder.and(
    builder.equal( men.get( Person_.gender ), Gender.MALE ),
    builder.equal( men.get( Person_.relationshipStatus ), RelationshipStatus.SINGLE )
);
Predicate womenRestriction = builder.and(
    builder.equal( women.get( Person_.gender ), Gender.FEMALE ),
    builder.equal( women.get( Person_.relationshipStatus ), RelationshipStatus.SINGLE )
);
query.where( builder.and( menRestriction, womenRestriction ) );