When the Filterable
API is not enough and you
need to have more control, you can make queries directly with the JPA Criteria
API. You may also need to customize sorting or joins, or otherwise modify the
query in some way. To do so, you need to implement a
QueryModifierDelegate
that the JPAContainer
entity provider calls when making a query. The easiest way to do this is to
extend DefaultQueryModifierDelegate
, which has empty
implementations of all the methods so that you can only override the ones you
need.
The entity provider calls specific
QueryModifierDelegate
methods at different
stages while making a query. The stages are:
Start building a query
Add "ORDER BY
" expression
Add "WHERE
" expression (filter)
Finish building a query
Methods where you can modify the query are called before and after each stage as listed in the following table:
Table 18.2. QueryModifierDelegate
Methods
queryWillBeBuilt() |
orderByWillBeAdded() |
orderByWasAdded() |
filtersWillBeAdded() |
filtersWereAdded() |
queryHasBeenBuilt() |
All the methods get two parameters. The
CriteriaBuilder
is a builder that you can use
to build queries. The CriteriaQuery
is the
query being built.
You can use the getRoots().iterator().next()
in
CriteriaQuery
to get the "root" that is
queried, for example, the PERSON
table, etc.
Let us consider a case where we modify the query for a
Person
container so that it includes only people
over 116. This trivial example is identical to the one given earlier using
the Filterable
interface.
persons.getEntityProvider().setQueryModifierDelegate( new DefaultQueryModifierDelegate () { @Override public void filtersWillBeAdded( CriteriaBuilder criteriaBuilder, CriteriaQuery<?> query, List<Predicate> predicates) { Root<?> fromPerson = query.getRoots().iterator().next(); // Add a "WHERE age > 116" expression Path<Integer> age = fromPerson.<Integer>get("age"); predicates.add(criteriaBuilder.gt(age, 116)); } });
When building queries, you should consider the capabilities of the different JPA implementations. Regarding Hibernate, see Section 18.9.3, “Joins in Hibernate vs EclipseLink”.