Aunque la respuesta dada por johncarl fue aceptada, no me parece correcta. Los JavaDocs para CriteriaQuery.where (dicen):
modificar la consulta para restringir el resultado de la consulta según la expresión booleana especificada. Reemplaza la (s) restricción (es) previamente agregada, si corresponde.
lo que tengo entendido, cada una de las siguientes líneas (dando restricciones) anulará las restricciones dadas anteriormente:
criteria.where(builder.like(langJoin.get(Language_.locale), locale));
criteria.where(builder.like(pRoot.get(Person_.name), name));
criteria.where(builder.between(pRoot.get(Person_.time), startDate, endDate));
Esto significa que al final sólo la última restricción (entre el inicio y la fecha de finalización) quedaría.
Yo sugiero threfore siguientes modificaciones a la respuesta de johncarl:
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Person> criteria = builder.createCriteria(Person.class);
Root<Person> pRoot = criteria.from(Person.class);
Join<Person, Language> langJoin = criteria.join("language", JoinType.LEFT);
Predicate[] restrictions = new Predicate[] {
builder.like(langJoin.get(Language_.locale), locale),
builder.like(pRoot.get(Person_.name), name),
builder.between(pRoot.get(Person_.time), startDate, endDate)
};
criteria.where(builder.and(restrictions));
criteria.orderBy(builder.asc(pRoot.get(Person_.name)));
Sin embargo, este código se ve muy feo! ¡Por favor, siéntase libre de editar si está mal y coméntelo si ve una mejor solución! ¡Sería gracioso!
¿Puede mostrar sus implementaciones para Persona e idioma? –