JPQL and the Criteria API
Query by entity and field names, then build the same query dynamically when you must.
Open this lesson in the learning hubKey points
- JPQL looks like SQL but names entities and fields:
select b from Book b where b.author.name = :n. - Dotted paths become joins automatically.
b.author.nameis an inner join, so books with no author quietly drop out. - Always bind values with
setParameter. Concatenating user input into a query is an injection hole here too. - For read-only screens select a DTO:
select new com.app.BookView(b.title, b.pages). Much lighter than loading entities. - The Criteria API builds the same query as objects. Verbose, but the right tool when the filters depend on user input.
- Generate the static metamodel (
Book_.title) so a renamed field breaks the build instead of production.
Example
// JPQL - fixed shape, readable
List<Book> hits = em.createQuery(
"select b from Book b where b.author.name = :name and b.pages > :min",
Book.class)
.setParameter("name", name)
.setParameter("min", 300)
.getResultList();
// Criteria - same query, assembled at runtime
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Book> query = cb.createQuery(Book.class);
Root<Book> book = query.from(Book.class);
List<Predicate> filters = new ArrayList<>();
if (name != null) {
filters.add(cb.equal(book.get(Book_.author).get(Author_.name), name));
}
if (minPages != null) {
filters.add(cb.gt(book.get(Book_.pages), minPages));
}
query.select(book).where(cb.and(filters.toArray(new Predicate[0])));
List<Book> dynamic = em.createQuery(query).getResultList();
JPQL for queries you know, Criteria for queries you assemble.
This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Hibernate course, and every lesson in it is listed on the Hibernate contents page.