Передача списка в IN clause NamedQuery JPA: решение, вопросы

Пройдите тест, узнайте какой профессии подходите

Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

Java
Скопировать код
TypedQuery<MyEntity> query = entityManager.createQuery(
    "SELECT e FROM MyEntity e WHERE e.myField IN :myList", MyEntity.class);
query.setParameter("myList", myList);
List<MyEntity> result = query.getResultList();

Свяжите ваш List с запросом посредством метода setParameter, заместив :myList местом для элементов списка в условии IN вашего JPQL-запроса. Это прозрачный, безопасный и эффективный подход!

Кинга Идем в IT: пошаговый план для смены профессии

О настройке безопасности с именованными запросами

Именованные запросы JPQL прекрасный этап оптимизации производительности. Они компилируются и анализируются единожды:

В классе сущности:

Java
Скопировать код
@Entity
@NamedQuery(name = "MyEntity.findByMyField",
            query = "SELECT e FROM MyEntity e WHERE e.myField IN :myList")
public class MyEntity { /* Вставьте сюда содержимое сущности */}

Выполнение именованного запроса:

Java
Скопировать код
TypedQuery<MyEntity> namedQuery = entityManager.createNamedQuery("MyEntity.findByMyField", MyEntity.class);
namedQuery.setParameter("myList", myList);
List<MyEntity> result = namedQuery.getResultList();

Берегитесь огромных списков

Огромные списки это отлично для гостевого списка на вечеринку, но не для запросов. Они могут вызвать трудности для базы данных. Но есть способы решить и эту проблему:

Java
Скопировать код
int batchSize = 1000; // Размер пакета можно настроить
List<MyEntity> allResults = new ArrayList<>();
for (int i = 0; i < myList.size(); i += batchSize) {
    List<MyEntity> batchList = myList.subList(i, Math.min(i + batchSize, myList.size()));
    query.setParameter("myList", batchList);
    allResults.addAll(query.getResultList());
}

Создание отличного кода на основе старых компонентов

Разработка с использованием старых версий Hibernate может натолкнуться на неприятные проблемы, например, известный баг. Мы подготовили решение!

Java
Скопировать код
List<MyEntity> result = entityManager.createQuery(
    "SELECT e FROM MyEntity e WHERE e.myField IN (:myList)", MyEntity.class)
    .setParameter("myList", myList.isEmpty() ? Collections.singletonList("null") : myList)
    .getResultList();

С помощью этой маленькой хитрости можно обойти проблему с пустым списком, добавив безопасное замещающее значение.

Визуализация

Представьте, что ваш JPQL-запрос – это образованный библиотекарь, а список в условии IN – это список желаемых книг читателя.

Книги в библиотеке (📚): ['Основы Java', 'Продвинутый Java', 'Java Concurrency']

Список книг читателя (📃): ['Java Concurrency']

Библиотекарь применяет условие IN:

SQL
Скопировать код
SELECT b FROM Book b WHERE b.title IN :titles

Найденные книги (🎉): ['Java Concurrency']

Великолепно, найдены именно те книги, которые были нужны, ничего лишнего.

Другой ракурс – Criteria API

Если JPQL кажется устаревшим, JPA Criteria API предлагает гибкий и типобезопасный способ динамического формирования запросов:

Java
Скопировать код
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<MyEntity> cq = cb.createQuery(MyEntity.class);
Root<MyEntity> root = cq.from(MyEntity.class);
cq.select(root).where(root.get("myField").in(myList));
List<MyEntity> result = entityManager.createQuery(cq).getResultList();

Этот подход особенно ценен при необходимости формирования запросов на ходу, исходя из переменных во время работы приложения.

Уделяйте внимание чистоте синтаксиса и эффективности

Тщательное составление JPQL может оказать существенное влияние на результаты. Не забывайте следовать синтаксису JPQL, и боги оптимизации встанут на вашу сторону! Следует также иметь в виду:

  • Пристраститесь к использованию TypedQuery для обеспечения типовой безопасности.
  • Хотите качественных решений? Предпочитайте определение NamedQuery над одноразовыми запросами.
  • Минимизация запросов к базе данных всегда должна быть на первом месте. Используйте параметризацию запросов и извлечение данных пакетами.

Полезные материалы

  1. Использование Criteria API для создания запросов — официальное руководство Oracle о создании типобезопасных запросов с использованием Criteria API.
  2. Spring Data JPA — справочник Spring Data JPA по созданию методов запросов.
  3. Руководство пользователя Hibernate ORM 5.4.33.Final — подробное описание использования запросов Criteria в Hibernate.
  4. Руководство Java Persistence API — об comprehensive характер походу к JPA, в том числе и Criteria API.
  5. Java Persistence/JPQL – Wikibooks — сообществом созданный ресурс, рассказывающий о JPQL, включая условие IN.