- Объединение Предикатов JPA И/Или Критериев
- 1. Обзор
- 2. Пример приложения
- 3. Объединение Двух Предикатов ИЛИ С Использованием Предиката И
- 4. Объединение двух предикатов И С использованием Предиката ИЛИ
- 5. Заключение
- Читайте ещё по теме:
- JPA — запрос с критерием. Использование API-интерфейса критериев JPA 2
- 2. Создание метамодели с использованием JPA-интерфейса критериев
- 3. Создание запроса с критерием
- 4. Тестирование запроса с критерием
- JPA Criteria API — Applying in() Predicate
- Example
- Entity
- Using in() methods
- Example Project
Объединение Предикатов JPA И/Или Критериев
Узнайте, как использовать API критериев JPA для реализации случаев использования, когда нам нужно было объединить И/ИЛИ предикаты.
1. Обзор
API критериев JPA можно использовать для простого добавления нескольких И/ИЛИ условий при запросе записей в базе данных. В этом руководстве мы рассмотрим краткий пример запросов критериев JPA, которые объединяют несколько предикатов И/ИЛИ предикатов.
Если вы не знакомы с предикатами, мы рекомендуем сначала прочитать об основных запросах критериев JPA.
2. Пример приложения
Для наших примеров мы рассмотрим инвентаризацию Элемент сущности, каждая из которых имеет идентификатор, | имя , цвет и класс :
3. Объединение Двух Предикатов ИЛИ С Использованием Предиката И
Давайте рассмотрим случай использования, когда нам нужно найти элементы, имеющие оба:
Мы можем легко сделать это с помощью API критериев JPA и() и или() составных предикатов .
Для начала давайте настроим ваш запрос:
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); CriteriaQuery- criteriaQuery = criteriaBuilder.createQuery(Item.class); Root
- 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- items = entityManager.createQuery(criteriaQuery).getResultList();
4. Объединение двух предикатов И С использованием Предиката ИЛИ
С другой стороны, давайте рассмотрим случай, когда нам нужно найти предметы, имеющие либо:
Логика довольно схожа, но здесь мы сначала создаем два И Предиката s, а затем объединяем их с помощью ИЛИ Предиката :
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); CriteriaQuery- criteriaQuery = criteriaBuilder.createQuery(Item.class); Root
- 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
- items = entityManager.createQuery(criteriaQuery).getResultList();
5. Заключение
В этом уроке мы использовали API критериев JPA для реализации случаев использования, когда нам нужно было объединить И/ИЛИ предикаты.
Как обычно, полный исходный код, используемый для этого урока, находится на GitHub .
Читайте ещё по теме:
JPA — запрос с критерием. Использование API-интерфейса критериев JPA 2
Настройки взяты из JPA – пример приложения Hello World, используемые здесь сущности взяты в измененной версии JPA – операции INSERT, UPDATE, DELETE.
2. Создание метамодели с использованием JPA-интерфейса критериев
Описание и генерацию метамодели для нашего примера вынес в отдельную статью — Создание метамодели для сущностного класса в JPA 2. Приведу полученный результат:
Как видите в сгенерированной метамодели используется аннотация @StaticMetamodel(ContactEntity.class) с указанием сущностного класса. Обратите внимание, что класс метамодели ContactEntity_.class лежит в том же пакете, что и сущность ContactEntity.class .
После создания метамодели появляется возможность создания запроса с критерием, который будет проверяться на этапе компиляции, а не во время выполнения, т.к. он строго типизирован.
3. Создание запроса с критерием
Создадим один метод для запроса с критерием JPA 2:
javax . persistence . criteria . CriteriaQuery
- Создаем экземпляр CriteriaBuilder с помощью вызова EntityManager.getCriteriaBuilder()
- Создаем типизированный запрос с помощью билдера, передавая параметром результирующий тип. Используется CriteriaQuery из пакета javax.persistence .
- Формируем основу для путевых выражений внутри запроса. Для этого вызывается CriteriaQuery.from() с передачей сущностного класса в качестве параметра. Результатом станет объект корня запроса Root .
- Root.fetch() обеспечивает незамедлительную выборку (по умолчанию в Hibernate (поставщик постоянства для JPA) — отложенная выборка). JoinType.LEFT — задает внешнее соединение. *Если вы читали предыдущие статьи, то выражение эквивалентно left join fetch в JPQL.
- Далее вызов CriteriaQuery.select() вместе с параметром корня запроса и методом distinct(true) . Последний метод устранит дублированные записи.
- Экземпляр Predicate — ограничение, которое указывает критерий выборки, определенный выражением. Может быть простым или сложным. Получаем с помощью вызова CriteriaBuilder.conjuction() .
- equal() — ожидаемо означает равенство. Внутри него вызывается Root.get() в котором передается атрибут метамодели сущностного класса, к которому будет применяться ограничение. CriteriaBuilder.and() объединяет предикат с существующим предикатом из переменной criteria .
- Полученный предикат со всеми ограничениями передается запросу с помощью CriteriaQuery.where() .
- Создаем и вызываем запрос.
4. Тестирование запроса с критерием
Простенький метод для вызова запроса с критерием:
JPA Criteria API — Applying in() Predicate
Following example shows how to use Expression.in() methods.
These methods test whether the expression is a member of the provided argument list.
package javax.persistence.criteria; . public interface Expression extends Selection < . Predicate in(Object. values); Predicate in(Expression. values); Predicate in(Collection values); Predicate in(Expressionvalues); . >
Example
Entity
@Entity public class Employee
Using in() methods
public class ExampleMain < private static EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("example-unit"); public static void main(String[] args) < try < persistEmployees(); findEmployeeBySalary(); findEmployeeByName(); findEmployeeByDept(); >finally < entityManagerFactory.close(); >> private static void findEmployeeBySalary() < System.out.println("-- Employees with salary IN 2000, 3000 and 4000 --"); EntityManager em = entityManagerFactory.createEntityManager(); CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder(); CriteriaQueryquery = criteriaBuilder.createQuery(Employee.class); Root employee = query.from(Employee.class); query.select(employee) .where(employee.get(Employee_.salary).in(2000, 3000, 4000)); TypedQuery typedQuery = em.createQuery(query); List resultList = typedQuery.getResultList(); resultList.forEach(System.out::println); em.close(); > //negating IN predicate private static void findEmployeeByName() < System.out.println("-- Employees name NOT IN Diana and Rose --"); EntityManager em = entityManagerFactory.createEntityManager(); CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder(); CriteriaQueryquery = criteriaBuilder.createQuery(Employee.class); Root employee = query.from(Employee.class); query.select(employee) .where(employee.get(Employee_.name).in("Diana", "Rose").not()); TypedQuery typedQuery = em.createQuery(query); List resultList = typedQuery.getResultList(); resultList.forEach(System.out::println); em.close(); > //using Predicate in(Expression. values); private static void findEmployeeByDept() < System.out.println("-- Employees dept IN IT, Sales and HR --"); EntityManager em = entityManagerFactory.createEntityManager(); CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder(); CriteriaQueryquery = criteriaBuilder.createQuery(Employee.class); Root employee = query.from(Employee.class); ParameterExpression deptParamExpression = criteriaBuilder.parameter(Collection.class); query.select(employee) .where(employee.get(Employee_.dept).in(deptParamExpression)); TypedQuery typedQuery = em.createQuery(query); typedQuery.setParameter(deptParamExpression, Arrays.asList("IT", "Sales", "HR")); List resultList = typedQuery.getResultList(); resultList.forEach(System.out::println); em.close(); > public static void persistEmployees() < Employee employee1 = Employee.create("Diana", "IT", 3000); Employee employee2 = Employee.create("Rose", "Sales", 2000); Employee employee3 = Employee.create("Denise", "Admin", 4000); Employee employee4 = Employee.create("Mike", "HR", 3500); EntityManager em = entityManagerFactory.createEntityManager(); em.getTransaction().begin(); em.persist(employee1); em.persist(employee2); em.persist(employee3); em.persist(employee4); em.getTransaction().commit(); em.close(); System.out.println("-- employees persisted --"); System.out.println(employee1); System.out.println(employee2); System.out.println(employee3); System.out.println(employee4); >>
-- employees persisted --
Employee
Employee
Employee
Employee
-- Employees with salary IN 2000, 3000 and 4000 --
Employee
Employee
Employee
-- Employees name NOT IN Diana and Rose --
Employee
Employee
-- Employees dept IN IT, Sales and HR --
Employee
Employee
Employee
Example Project
Dependencies and Technologies Used:
- h2 1.4.197: H2 Database Engine.
- hibernate-core 5.3.6.Final: Hibernate’s core ORM functionality.
Implements javax.persistence:javax.persistence-api version 2.2 - hibernate-jpamodelgen 5.3.6.Final: Annotation Processor to generate JPA 2 static metamodel classes.
- JDK 1.8
- Maven 3.5.4