Querying with the Criteria API

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:

  1. Start building a query

  2. Add " ORDER BY" expression

  3. Add " WHERE" expression (filter)

  4. 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 1. 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.

Filtering the Query

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));
    }
});

Compatibility

When building queries, you should consider the capabilities of the different JPA implementations. Regarding Hibernate, see "Joins in Hibernate vs EclipseLink".