Автор оригинала: Vlad Mihalcea.
Вступление
В этой статье я собираюсь показать вам, как вы можете вернуть результат Java-карты при выполнении запроса JPA. Я решил написать эту статью после ответа на аналогичный вопрос о StackOverflow .
Как вернуть результат #Java Map при выполнении запроса JPA. https://t.co/8zhtAr4jTN pic.twitter.com/G09xmtS9Xh
Модель предметной области
Предполагая, что мы используем следующую сущность Post , которая имеет атрибут CreatedOn типа LocalDate Java:
И мы сохранили следующую Запись сущность в нашей базе данных:
entityManager.persist(
new Post()
.setId(1L)
.setTitle(
"High-Performance Java Persistence eBook " +
"has been released!"
)
.setCreatedOn(LocalDate.of(2016, 8, 30))
);
entityManager.persist(
new Post()
.setId(2L)
.setTitle(
"High-Performance Java Persistence paperback " +
"has been released!"
)
.setCreatedOn(LocalDate.of(2016, 10, 12))
);
entityManager.persist(
new Post()
.setId(3L)
.setTitle(
"High-Performance Java Persistence Mach 1 video course " +
"has been released!"
)
.setCreatedOn(LocalDate.of(2018, 1, 30))
);
entityManager.persist(
new Post()
.setId(4L)
.setTitle(
"High-Performance Java Persistence Mach 2 video course " +
"has been released!"
)
.setCreatedOn(LocalDate.of(2018, 5, 8))
);
entityManager.persist(
new Post()
.setId(5L)
.setTitle(
"Hypersistence Optimizer " +
"has been released!"
)
.setCreatedOn(LocalDate.of(2019, 3, 19))
);
Подсчет сообщений, опубликованных за год
Теперь мы хотим создать отчет, в котором будет отображаться количество сообщений по годам их публикации. Для этого мы можем использовать следующий JPQL-запрос:
select
YEAR(p.createdOn) as year,
count(p) as postCount
from
Post p
group by
YEAR(p.createdOn)
Традиционно метод getResultList JPA Запрос использовался всякий раз, когда результирующий набор содержал несколько строк. Однако мы не хотим возвращать Список при выполнении этого запроса. Поскольку у нас есть проекция двух столбцов, где первый из них уникален, нам лучше вместо этого вернуть Карту .
Возврат результата карты с помощью JPA-запроса getResultStream
Как я объяснил в этой статье , вы можете использовать JPA 2.2 getResultStream для преобразования Списка<Кортеж> результата в Карту<Целое число, Целое число> :
MappostCountByYearMap = entityManager .createQuery( "select " + " YEAR(p.createdOn) as year, " + " count(p) as postCount " + "from " + " Post p " + "group by " + " YEAR(p.createdOn)", Tuple.class) .getResultStream() .collect( Collectors.toMap( tuple -> ((Number) tuple.get("year")).intValue(), tuple -> ((Number) tuple.get("postCount")).intValue() ) );
Метод Collectors.toMap возвращает Collector , который возвращает Хэш-карту с ключом, отображенным первой предоставленной лямбда – функцией, и значением, отображенным второй лямбда-функцией.
Возврат результата карты с помощью JPA-запроса getResultList
Если вы используете JPA 2.1 или более старые версии, но ваше приложение работает на Java 8 или более новой версии, вы можете использовать getResultList и преобразовать Список<Кортеж> в поток Java 8:
MappostCountByYearMap = entityManager .createQuery( "select " + " YEAR(p.createdOn) as year, " + " count(p) as postCount " + "from " + " Post p " + "group by " + " YEAR(p.createdOn)", Tuple.class) .getResultList() .stream() .collect( Collectors.toMap( tuple -> ((Number) tuple.get("year")).intValue(), tuple -> ((Number) tuple.get("postCount")).intValue() ) );
Возврат результата карты с помощью преобразователя результатов, зависящего от режима гибернации
Другой вариант-использовать класс Map ResultTransformer , предоставляемый проектом Hibernate Types с открытым исходным кодом:
MappostCountByYearMap = (Map ) entityManager .createQuery( "select " + " YEAR(p.createdOn) as year, " + " count(p) as postCount " + "from " + " Post p " + "group by " + " YEAR(p.createdOn)") .unwrap(org.hibernate.query.Query.class) .setResultTransformer( new MapResultTransformer () ) .getSingleResult();
Преобразователь результатов карты подходит для проектов, все еще работающих на Java 6 или использующих более старые версии Hibernate.
Вывод
Как JPA, так и Hibernate обеспечивают большую гибкость, когда дело доходит до преобразования результирующего набора данного запроса JPG, будь то JPQL, API критериев или собственный SQL-запрос.
Если заданная ГРУППА JPA ПО запросу возвращает только два столбца, один из которых уникален, очень удобно возвращать результат в виде карты Java. Для этого вы можете использовать либо функцию потока Java, либо преобразователь результатов, зависящий от режима гибернации .