Hibernate.orgCommunity Documentation
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.
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.
This the most used form of query in Hibernate Query Language (HQL) and Hibernate Criteria Queries. You have an entity and you want to select one or more of that entity based on some condition.
Example 9.1. Selecting the root entity
CriteriaQuery<Person> criteria = builder.createQuery( Person.class ); Root<Person> personRoot = criteria.from( Person.class ); criteria.select( personRoot ); criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), "brown" ) ); List<Person> people = em.createQuery( criteria ).getResultList(); for ( Person person : people ) { ... }
We use the form createQuery( Person.class ) here because the expected returns are in fact Person entities as we see when we begin processing the results. | |
personCriteria.select( personRoot ) here is completely unneeded in this specific case because of the fact that personRoot will be the implied selection since we have only a single root. It was done here only for completeness of an example | |
Person_.eyeColor is an example of the static form of metamodel reference. We will use that form exclusively in this chapter. See Section 4.1, “Static metamodel” for details. |
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.
Example 9.2. Selecting an attribute
CriteriaQuery<Integer> criteria = builder.createQuery( Integer.class ); Root<Person> personRoot = criteria.from( Person.class ); criteria.select( personRoot.get( Person_.age ) ); criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), "brown" ) ); List<Integer> ages = em.createQuery( criteria ).getResultList(); for ( Integer age : ages ) { ... }
Notice again the typing of the query based on the
anticipated result type(s). Here we are specifying
| |
We need to bind the fact that we are interested in the age associated with the personRoot. We might have multiple references to the Person entity in the query so we need to identify (aka qualify) which Person#age we mean. |
Example 9.3. Selecting an expression
CriteriaQuery<Integer> criteria = builder.createQuery( Integer.class ); Root<Person> personRoot = criteria.from( Person.class ); criteria.select( builder.max( personRoot.get( Person_.age ) ) ); criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), "brown" ) ); Integer maxAge = em.createQuery( criteria ).getSingleResult();
Here we see
|
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”
Example 9.4. Selecting an array
CriteriaQuery<Object[]> criteria = builder.createQuery( Object[].class ); Root<Person> personRoot = criteria.from( Person.class ); Path<Long> idPath = personRoot.get( Person_.id ); Path<Integer> agePath = personRoot.get( Person_.age ); criteria.select( builder.array( idPath, agePath ) ); criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), "brown" ) ); List<Object[]> valueArray = em.createQuery( criteria ).getResultList(); for ( Object[] values : valueArray ) { final Long id = (Long) values[0]; final Integer age = (Integer) values[1]; ... }
Technically this is classified as a typed query, but as you can see in handling the results that is sort of misleading. Anyway, the expected result type here is an array. | |
Here we see the use of the |
Example 9.5. Selecting an array (2)
CriteriaQuery<Object[]> criteria = builder.createQuery( Object[].class ); Root<Person> personRoot = criteria.from( Person.class ); Path<Long> idPath = personRoot.get( Person_.id ); Path<Integer> agePath = personRoot.get( Person_.age ); criteria.multiselect( idPath, agePath ); criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), "brown" ) ); List<Object[]> valueArray = em.createQuery( criteria ).getResultList(); for ( Object[] values : valueArray ) { final Long id = (Long) values[0]; final Integer age = (Integer) values[1]; ... }
Just as we saw in Example 9.4, “Selecting an array” we have a "typed" criteria query returning an Object array. | |
This actually functions exactly the same as what we saw in
Example 9.4, “Selecting an array”. The
|
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.
Example 9.6. Selecting an wrapper
public class PersonWrapper { private final Long id; private final Integer age; public PersonWrapper(Long id, Integer age) { this.id = id; this.age = age; } ... } ... CriteriaQuery<PersonWrapper> criteria = builder.createQuery( PersonWrapper.class ); Root<Person> personRoot = criteria.from( Person.class ); criteria.select( builder.construct( PersonWrapper.class, personRoot.get( Person_.id ), personRoot.get( Person_.age ) ) ); criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), "brown" ) ); List<PersonWrapper> people = em.createQuery( criteria ).getResultList(); for ( PersonWrapper person : people ) { ... }
First we see the simple definition of the wrapper object we will be using to wrap our result values. Specifically notice the constructor and its argument types. | |
Since we will be returning PersonWrapper objects, we use PersonWrapper as the type of our criteria query. | |
Here we see another new
|
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.
Example 9.7. Selecting a tuple
CriteriaQuery<Tuple> criteria = builder.createTupleQuery(); Root<Person> personRoot = criteria.from( Person.class ); Path<Long> idPath = personRoot.get( Person_.id ); Path<Integer> agePath = personRoot.get( Person_.age ); criteria.multiselect( idPath, agePath ); criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), "brown" ) ); List<Tuple> tuples = em.createQuery( criteria ).getResultList(); for ( Tuple tuple : valueArray ) { assert tuple.get( 0 ) == tuple.get( idPath ); assert tuple.get( 1 ) == tuple.get( agePath ); ... }
Here we see the use of a new
| |
Again we see the use of the
| |
Here we see
|
The javax.persistence.Tuple
contract provides 3 basic forms of access to the underlying
elements:
<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
.
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.
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] |
All the individual parts of the FROM clause (roots, joins, paths)
implement the
javax.persistence.criteria.From
interface.
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>)
Example 9.8. Adding a root
CriteriaQuery<Person> personCriteria = builder.createQuery( Person.class );
// create and add the root
person.from( Person.class );
...
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 ) );
Joins allow navigation from other
javax.persistence.criteria.From
to either
association or embedded attributes. Joins are created by the numerous
overloaded join
methods of the
javax.persistence.criteria.From
interface:
Example 9.9. Example with Embedded and ManyToOne
CriteriaQuery<Person> personCriteria = builder.createQuery( Person.class );
Root<Person> personRoot = person.from( Person.class );
// Person.address is an embedded attribute
Join<Person,Address> personAddress = personRoot.join( Person_.address );
// Address.country is a ManyToOne
Join<Address,Country> addressCountry = personAddress.join( Address_.country );
...
Example 9.10. Example with Collections
CriteriaQuery<Person> personCriteria = builder.createQuery( Person.class );
Root<Person> personRoot = person.from( Person.class );
Join<Person,Order> orders = personRoot.join( Person_.orders );
Join<Order,LineItem> orderLines = orders.join( Order_.lineItems );
...
Just like in HQL and EJB-QL, we can specify that associated data
be fetched along with the owner. Fetches are created by the numerous
overloaded fetch
methods of the
javax.persistence.criteria.From
interface:
Example 9.11. Example with Embedded and ManyToOne
CriteriaQuery<Person> personCriteria = builder.createQuery( Person.class );
Root<Person> personRoot = person.from( Person.class );
// Person.address is an embedded attribute
Join<Person,Address> personAddress = personRoot.fetch( Person_.address );
// Address.country is a ManyToOne
Join<Address,Country> addressCountry = personAddress.fetch( Address_.country );
...
Technically speaking, embedded attributes are always fetched
with their owner. However in order to define the fetching of
Address#country we needed a
javax.persistence.criteria.Fetch
for
its parent path.
Example 9.12. Example with Collections
CriteriaQuery<Person> personCriteria = builder.createQuery( Person.class );
Root<Person> personRoot = person.from( Person.class );
Join<Person,Order> orders = personRoot.fetch( Person_.orders );
Join<Order,LineItem> orderLines = orders.fetch( Order_.lineItems );
...
Example 9.13. Using parameters
CriteriaQuery<Person> criteria = build.createQuery( Person.class ); Root<Person> personRoot = criteria.from( Person.class ); criteria.select( personRoot ); ParameterExpression<String> eyeColorParam = builder.parameter( String.class ); criteria.where( builder.equal( personRoot.get( Person_.eyeColor ), eyeColorParam ) ); TypedQuery<Person> query = em.createQuery( criteria ); query.setParameter( eyeColorParam, "brown" ); List<Person> people = query.getResultList();
Use the | |
Use the parameter reference in the criteria query. | |
Use the parameter reference to bind the parameter value to
the
|
Copyright © 2005 Red Hat Inc. and the various authors