Передача списка в IN clause NamedQuery JPA: решение, вопросы
Быстрый ответ
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-запроса. Это прозрачный, безопасный и эффективный подход!
О настройке безопасности с именованными запросами
Именованные запросы JPQL прекрасный этап оптимизации производительности. Они компилируются и анализируются единожды:
В классе сущности:
@Entity
@NamedQuery(name = "MyEntity.findByMyField",
query = "SELECT e FROM MyEntity e WHERE e.myField IN :myList")
public class MyEntity { /* Вставьте сюда содержимое сущности */}
Выполнение именованного запроса:
TypedQuery<MyEntity> namedQuery = entityManager.createNamedQuery("MyEntity.findByMyField", MyEntity.class);
namedQuery.setParameter("myList", myList);
List<MyEntity> result = namedQuery.getResultList();
Берегитесь огромных списков
Огромные списки это отлично для гостевого списка на вечеринку, но не для запросов. Они могут вызвать трудности для базы данных. Но есть способы решить и эту проблему:
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 может натолкнуться на неприятные проблемы, например, известный баг. Мы подготовили решение!
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:
SELECT b FROM Book b WHERE b.title IN :titles
Найденные книги (🎉): ['Java Concurrency']
Великолепно, найдены именно те книги, которые были нужны, ничего лишнего.
Другой ракурс – Criteria API
Если JPQL кажется устаревшим, JPA Criteria API предлагает гибкий и типобезопасный способ динамического формирования запросов:
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 над одноразовыми запросами.
- Минимизация запросов к базе данных всегда должна быть на первом месте. Используйте параметризацию запросов и извлечение данных пакетами.
Полезные материалы
- Использование Criteria API для создания запросов — официальное руководство Oracle о создании типобезопасных запросов с использованием Criteria API.
- Spring Data JPA — справочник Spring Data JPA по созданию методов запросов.
- Руководство пользователя Hibernate ORM 5.4.33.Final — подробное описание использования запросов Criteria в Hibernate.
- Руководство Java Persistence API — об comprehensive характер походу к JPA, в том числе и Criteria API.
- Java Persistence/JPQL – Wikibooks — сообществом созданный ресурс, рассказывающий о JPQL, включая условие IN.