Some APIs have left a bad taste in us. We changed the order of some calls, and suddenly nothing worked any more. We forgot to use the return of some method, and it unexpectedly threw an exception.
The JPA Criteria API is relatively mature concerning such problems. Nevertheless I would like to capture the answers to some questions that left me with some uncertainty when I started to work with that API.
select()
, where()
, orderBy()
, ... in the same order as an SQL query would require, or can I call them in any order?CriteriaQuery
object, do I have to use that return for further actions, or can I use the initial instance for all subsequent calls?select()
, where()
, orderBy()
, ... a second time, would they overwrite any preceding call, or add to them?Due to unknown communication problems, developers are used to trying out everything by themselves. So did I, here comes my test.
You find the entities used in this example in my recent article about JOIN-types.
Following is a query that joins two tables and uses select()
, where()
, orderBy()
in an unusual order, and uses the return from last call as final query:
1 | final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); |
It is not necessary to use the query returned by the calls to CriteriaQuery
, like I do here with completeQuery
. All methods return the very query instance they were called on, this programming style is called fluent interface.
Also it is not necessary to keep the calls in a specific order. Following query delivers exactly the same result as the first one, although implemented in a different way:
1 | final CriteriaBuilder cb = entityManager.getCriteriaBuilder(); |
In this second example, on line 6, I call multiselect()
for selecting several fields instead of an object. On line 7, I call the same method again, but with different parameters. This demonstrates a problem with fluent interface: do subsequent calls replace any preceding call, or do they merge into it, or would they cause an exception? As you can see by the inline comment, they replace. This is also documented in JavaDoc. Thus several calls to the same method of CriteriaQuery
do not make sense, because they overwrite each other.
Rules of thumb:
CriteriaBuilder
from EntityManager
CriteriaQuery
with a result-type from CriteriaBuilder
from()
with a root-type on the CriteriaQuery
to get a query-root, used to name attributes in where()
and othersjoin()
select()
or multiselect()
, where()
, orderBy()
, groupBy()
, having()
, either one-by-one or in fluent interface style, in any order, but each just onceCriteriaQuery
into a TypedQuery
using the EntityManager
, and actually read some result from database.Key to understanding the API is that calls to CriteriaQuery
just build a query, they do not yet read anything from database. Reading is done by the final entityManager.createQuery(criteriaQuery).getResultList()
call.
ɔ⃝ Fritz Ritzberger, 2020-01-28