In JPA2 there is a query API referred to as "criteria". This is really an API allowing
the construction of queries expression by expression, and optionally making it type safe
so that if you refactor a field name then it is changed in the queries.
To use the JPA Criteria API, firstly you need to create a
CriteriaQuery
object for the
candidate in question, and set the candidate, its alias, and the result to be of the candidate
type
CriteriaBuilder cb = emf.getCriteriaBuilder();
CriteriaQuery<Person> crit = cb.createQuery(Person.class);
Root<Person> candidateRoot = crit.from(Person.class);
candidateRoot.alias("p");
crit.select(candidateRoot);
So what we have there equates to
SELECT p FROM mydomain.Person p
For a complete list of all methods available on CriteriaBuilder, refer to
For a complete list of all methods available on CriteriaQuery, refer to
If you ever want to know what is the equivalent JPQL string-based query for your Criteria,
just print out
criteriaQuery.toString()
.
This is
not
part of the JPA spec, but something that we feel is very useful so is
provided as a DataNucleus vendor extension. So, for example, the criteria query above would
result in the following from
crit.toString()
SELECT p FROM mydomain.Person p
The basic Criteria query above is fine, but you may want to define a result other than the
candidate. To do this we need to use the Criteria API.
Path nameField = candidateRoot.get("name");
crit.select(nameField);
which equates to
The basic Criteria query above is fine, but you may want to define some explicit joins.
To do this we need to use the Criteria API.
Metamodel model = emf.getMetamodel();
ManagedType personType = model.type(Person.class);
Attribute addressAttr = personType.getAttribute("address");
Join addressJoin = candidateRoot.join((SingularAttribute)addressAttr);
addressJoin.alias("a");
which equates to
FROM mydomain.Person p JOIN p.address a
The basic Criteria query above is fine, but in the majority of cases we want to
define a filter. To do this we need to use the Criteria API.
Path nameField = candidateRoot.get("name");
Predicate nameEquals = cb.equal(nameField, "First");
crit.where(nameEquals);
You can also invoke methods, so a slight variation on this clause would be
Predicate nameUpperEquals = cb.equal(cb.upper(nameField), "FIRST");
which equates to
WHERE (UPPER(p.name) = 'FIRST')
The basic Criteria query above is fine, but in many cases we want to define ordering.
To do this we need to use the Criteria API.
Path nameField = candidateRoot.get("name");
Order orderFirstName = cb.desc(nameField);
crit.orderBy(orderFirstName);
which equates to
Another common thing we would want to do is specify input parameters.
To do this we need to use the Criteria API. Let's take an example of a filter with parameters.
Path nameField = candidateRoot.get("name");
ParameterExpression param1 = cb.parameter(String.class, "myParam1");
Predicate nameEquals = cb.equal(nameField, param1);
crit.where(nameEquals);
which equates to
WHERE (p.name = :myParam)
Don't forget to set the value of the parameters before executing the query!
Ok, so we've seen how to generate a Criteria query. So how can we execute it ?
This is simple; convert it into a standard JPA query, set any parameter values and execute it.
Query query = em.createQuery(crit);
List<Person> results = query.getResultList();