Автор оригинала: 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, либо преобразователь результатов, зависящий от режима гибернации .