Перейти к основному содержимому

Запросы критериев JPA

· 5 мин. чтения

1. Обзор

В этом уроке мы обсудим очень полезную функцию JPA — Criteria Queries.

Это позволяет нам писать запросы, не выполняя необработанный SQL, а также дает нам некоторый объектно-ориентированный контроль над запросами, что является одной из основных функций Hibernate. Criteria API позволяет нам создавать объект запроса критериев программно, где мы можем применять различные виды правил фильтрации и логических условий.

Начиная с Hibernate 5.2, API-интерфейс Hibernate Criteria устарел, и новые разработки сосредоточены на API-интерфейсе JPA Criteria. Мы рассмотрим, как использовать Hibernate и JPA для построения запросов Criteria.

2. Зависимости Maven

Чтобы проиллюстрировать API, мы будем использовать эталонную реализацию JPA Hibernate.

Чтобы использовать Hibernate, мы обязательно добавим его последнюю версию в наш файл pom.xml :

<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.3.2.Final</version>
</dependency>

Мы можем найти последнюю версию Hibernate здесь.

3. Простой пример с использованием критериев

Давайте начнем с рассмотрения того, как извлекать данные с помощью запросов Criteria. Мы рассмотрим, как получить все экземпляры определенного класса из базы данных.

У нас есть класс Item , представляющий кортеж «ITEM» в базе данных:

public class Item implements Serializable {

private Integer itemId;
private String itemName;
private String itemDescription;
private Integer itemPrice;

// standard setters and getters
}

Давайте рассмотрим простой запрос критериев, который извлечет все строки «ПУНКТ» из базы данных:

Session session = HibernateUtil.getHibernateSession();
CriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<Item> cr = cb.createQuery(Item.class);
Root<Item> root = cr.from(Item.class);
cr.select(root);

Query<Item> query = session.createQuery(cr);
List<Item> results = query.getResultList();

Приведенный выше запрос является простой демонстрацией того, как получить все элементы. Давайте посмотрим это шаг за шагом:

  1. Создайте экземпляр Session из объекта SessionFactory.
  2. Создайте экземпляр C riteriaBuilder , вызвав метод getCriteriaBuilder ().
  3. Создайте экземпляр CriteriaQuery , вызвав метод createQuery () CriteriaBuilder . ``
  4. Создайте экземпляр Query , вызвав метод createQuery ( ) сеанса.
  5. Вызов метода getResultList() объекта запроса , который дает нам результаты

Теперь, когда мы рассмотрели основы, давайте перейдем к некоторым особенностям запроса критериев.

3.1. Использование выражений

CriteriaBuilder можно использовать для ограничения результатов запроса на основе определенных условий `` с помощью метода CriteriaQuery where() и предоставления выражений , созданных CriteriaBuilder .

Давайте посмотрим на некоторые примеры часто используемых выражений .

Для того, чтобы получить предметы стоимостью более 1000:

cr.select(root).where(cb.gt(root.get("itemPrice"), 1000));

Далее, получение предметов с itemPrice меньше 1000:

cr.select(root).where(cb.lt(root.get("itemPrice"), 1000));

Элементы, имеющие itemName , содержат Chair :

cr.select(root).where(cb.like(root.get("itemName"), "%chair%"));

Записи, имеющие itemPrice от 100 до 200:

cr.select(root).where(cb.between(root.get("itemPrice"), 100, 200));

Предметы, имеющие itemName в Skate Board , Paint and Glue :

cr.select(root).where(root.get("itemName").in("Skate Board", "Paint", "Glue"));

Чтобы проверить, является ли данное свойство нулевым:

cr.select(root).where(cb.isNull(root.get("itemDescription")));

Чтобы проверить, не является ли данное свойство нулевым:

cr.select(root).where(cb.isNotNull(root.get("itemDescription")));

Мы также можем использовать методы isEmpty() и isNotEmpty() , чтобы проверить, является ли список внутри класса пустым или нет.

Кроме того, мы можем объединить два или более из приведенных выше сравнений. Criteria API позволяет нам легко связывать выражения :

Predicate[] predicates = new Predicate[2];
predicates[0] = cb.isNull(root.get("itemDescription"));
predicates[1] = cb.like(root.get("itemName"), "chair%");
cr.select(root).where(predicates);

Чтобы добавить два выражения с логическими операциями:

Predicate greaterThanPrice = cb.gt(root.get("itemPrice"), 1000);
Predicate chairItems = cb.like(root.get("itemName"), "Chair%");

Элементы с определенными выше условиями, объединенными логическим ИЛИ :

cr.select(root).where(cb.or(greaterThanPrice, chairItems));

Чтобы получить элементы, соответствующие определенным выше условиям, объединенным логическим И :

cr.select(root).where(cb.and(greaterThanPrice, chairItems));

3.2. Сортировка

Теперь, когда мы знаем основы использования Criteria , давайте посмотрим на функции сортировки Criteria .

В следующем примере мы упорядочиваем список в порядке возрастания имени, а затем в порядке убывания цены:

cr.orderBy(
cb.asc(root.get("itemName")),
cb.desc(root.get("itemPrice")));

В следующем разделе мы рассмотрим, как выполнять агрегатные функции.

3.3. Проекции, агрегаты и группирующие функции

Теперь давайте посмотрим на различные агрегатные функции.

Получить количество строк:

CriteriaQuery<Long> cr = cb.createQuery(Long.class);
Root<Item> root = cr.from(Item.class);
cr.select(cb.count(root));
Query<Long> query = session.createQuery(cr);
List<Long> itemProjected = query.getResultList();

Ниже приведен пример агрегатных функций — Агрегатная функция для среднего :

CriteriaQuery<Double> cr = cb.createQuery(Double.class);
Root<Item> root = cr.from(Item.class);
cr.select(cb.avg(root.get("itemPrice")));
Query<Double> query = session.createQuery(cr);
List avgItemPriceList = query.getResultList();

Другими полезными агрегатными методами являются sum() , max() , min() , count() и т. д. ** ** ``

3.4. Обновление критериев

Начиная с JPA 2.1, поддерживается выполнение обновлений базы данных с использованием Criteria API.

CriteriaUpdate имеет метод set() , который можно использовать для предоставления новых значений для записей базы данных:

CriteriaUpdate<Item> criteriaUpdate = cb.createCriteriaUpdate(Item.class);
Root<Item> root = criteriaUpdate.from(Item.class);
criteriaUpdate.set("itemPrice", newPrice);
criteriaUpdate.where(cb.equal(root.get("itemPrice"), oldPrice));

Transaction transaction = session.beginTransaction();
session.createQuery(criteriaUpdate).executeUpdate();
transaction.commit();

В приведенном выше фрагменте мы создаем экземпляр CriteriaUpdate<Item> из CriteriaBuilder и используем его метод set() для предоставления новых значений для itemPrice . Чтобы обновить несколько свойств, нам просто нужно несколько раз вызвать метод set() .

3.5. КритерииУдалить

CriteriaDelete включает операцию удаления с помощью Criteria API.

Нам просто нужно создать экземпляр CriteriaDelete и использовать метод where() для применения ограничений:

CriteriaDelete<Item> criteriaDelete = cb.createCriteriaDelete(Item.class);
Root<Item> root = criteriaDelete.from(Item.class);
criteriaDelete.where(cb.greaterThan(root.get("itemPrice"), targetPrice));

Transaction transaction = session.beginTransaction();
session.createQuery(criteriaDelete).executeUpdate();
transaction.commit();

4. Преимущество над HQL

В предыдущих разделах мы рассмотрели, как использовать запросы с критериями.

Очевидно, что главное и наиболее весомое преимущество Criteria Queries по сравнению с HQL — приятный, чистый, объектно-ориентированный API.

Мы можем просто писать более гибкие динамические запросы по сравнению с простым HQL. Логика может быть реорганизована с помощью IDE и обладает всеми преимуществами безопасности типов самого языка Java.

Конечно, есть и некоторые недостатки, особенно в отношении более сложных соединений.

Таким образом, нам обычно приходится использовать лучший инструмент для работы — в большинстве случаев это может быть Criteria API, но определенно есть случаи, когда нам придется перейти на более низкий уровень.

5. Вывод

В этой статье мы сосредоточились на основах запросов Criteria в Hibernate и JPA, а также на некоторых дополнительных функциях API.

Обсуждаемый здесь код доступен в репозитории GitHub .