«1. Обзор
API критериев JPA можно использовать для простого добавления нескольких условий И/ИЛИ при запросе записей в базе данных. В этом руководстве мы рассмотрим быстрый пример запросов критериев JPA, которые объединяют несколько предикатов AND/OR.
Если вы не знакомы с предикатами, рекомендуем сначала прочитать об основных критериальных запросах JPA.
2. Пример приложения
В наших примерах мы рассмотрим перечень сущностей Item, каждая из которых имеет идентификатор, имя, цвет и класс:
@Entity
public class Item {
@Id
private Long id;
private String color;
private String grade;
private String name;
// standard getters and setters
}
3. Объединение двух предикатов ИЛИ с использованием AND Predicate
Давайте рассмотрим случай использования, когда нам нужно найти элементы, имеющие оба:
- red or blue color
AND - A or B grade
Мы можем легко сделать это, используя составные предикаты and() и or() API JPA Criteria.
Для начала давайте настроим наш запрос:
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Item> criteriaQuery = criteriaBuilder.createQuery(Item.class);
Root<Item> itemRoot = criteriaQuery.from(Item.class);
Теперь нам нужно построить предикат для поиска элементов, имеющих синий или красный цвет:
Predicate predicateForBlueColor
= criteriaBuilder.equal(itemRoot.get("color"), "blue");
Predicate predicateForRedColor
= criteriaBuilder.equal(itemRoot.get("color"), "red");
Predicate predicateForColor
= criteriaBuilder.or(predicateForBlueColor, predicateForRedColor);
Далее, давайте создадим Предикат для поиска элементов класса A или B:
Predicate predicateForGradeA
= criteriaBuilder.equal(itemRoot.get("grade"), "A");
Predicate predicateForGradeB
= criteriaBuilder.equal(itemRoot.get("grade"), "B");
Predicate predicateForGrade
= criteriaBuilder.or(predicateForGradeA, predicateForGradeB);
Наконец, мы определяем предикат И для этих двух, применяем метод where() и выполняем наш запрос:
Predicate finalPredicate
= criteriaBuilder.and(predicateForColor, predicateForGrade);
criteriaQuery.where(finalPredicate);
List<Item> items = entityManager.createQuery(criteriaQuery).getResultList();
4. Объединение двух И Предикаты с использованием предиката ИЛИ
С другой стороны, давайте рассмотрим случай, когда нам нужно найти элементы, имеющие:
- red color and grade D
OR - blue color and grade B
Логика очень похожа, но здесь мы сначала создаем два предиката И, а затем объединяем их, используя ИЛИ Predicate:
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Item> criteriaQuery = criteriaBuilder.createQuery(Item.class);
Root<Item> itemRoot = criteriaQuery.from(Item.class);
Predicate predicateForBlueColor
= criteriaBuilder.equal(itemRoot.get("color"), "red");
Predicate predicateForGradeA
= criteriaBuilder.equal(itemRoot.get("grade"), "D");
Predicate predicateForBlueColorAndGradeA
= criteriaBuilder.and(predicateForBlueColor, predicateForGradeA);
Predicate predicateForRedColor
= criteriaBuilder.equal(itemRoot.get("color"), "blue");
Predicate predicateForGradeB
= criteriaBuilder.equal(itemRoot.get("grade"), "B");
Predicate predicateForRedColorAndGradeB
= criteriaBuilder.and(predicateForRedColor, predicateForGradeB);
Predicate finalPredicate
= criteriaBuilder
.or(predicateForBlueColorAndGradeA, predicateForRedColorAndGradeB);
criteriaQuery.where(finalPredicate);
List<Item> items = entityManager.createQuery(criteriaQuery).getResultList();
5. Заключение
В этом руководстве мы использовали JPA Criteria API для реализации вариантов использования, в которых нам нужно было комбинировать предикаты AND/OR.
Как обычно, полный исходный код, используемый для этого руководства, находится на GitHub.