Иногда удобно извлечь из базы данные в вид Map. Например, если запрос содержит group by. Ниже рассмотрим, как это сделать.
Модель
Допустим, в таблице хранятся доходы — сумма дохода и дата дохода. Доходы относятся к разным годам, а мы хотим посчитать общую сумму дохода за каждый год.
Сущность Income, в которой хранятся доходы:
@Data @NoArgsConstructor @Entity public class Income { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE) private long id; private LocalDate localDate; private int sum; }
JPQL-запрос с group by
JPQL-запрос для получения общей суммы дохода по каждому году будет таким:
select year(i.localDate) as year, sum(i.sum) as sum from Income i group by year
Обычно Query возвращает List:
List<Tuple> list=em.createQuery("select year(i.localDate) as year, sum(i.sum) as sum from Income i group by year").getResultList();
Но нам надо получить Map. Есть несколько способов.
С помощью getResultStream()
Map<Integer, Integer> map=em.createQuery("select year(i.localDate) as year, sum(i.sum) as sum from Income i group by year", Tuple.class) .getResultStream() .collect( Collectors.toMap( tuple -> ((Number) tuple.get("year")).intValue(), tuple -> ((Number) tuple.get("sum")).intValue() ) );
getResultList() в Stream
Либо ResultList преобразуем в Stream:
Map<Integer, Integer> map=em.createQuery("select year(i.localDate) as year, sum(i.sum) as sum from Income i group by year", Tuple.class) .getResultList() .stream() .collect( Collectors.toMap( tuple -> ((Number) tuple.get("year")).intValue(), tuple -> ((Number) tuple.get("sum")).intValue() ) );
С помощью ResultTransformer из библиотеки
Есть также библиотека hibernate-types, в которой реализован специальный MapResultTransformer. Его тоже можно использовать:
Map<Integer, Integer> map= (Map<Integer, Integer>) em.createQuery("select year(i.localDate) as year, sum(i.sum) as sum from Income i group by year") .unwrap(org.hibernate.query.Query.class) .setResultTransformer( new MapResultTransformer<>() ) .getSingleResult();
Другой пример реализации ResultTransformer рассмотрен в статье о получении проекций.
Исходный код
Исходный код примера есть на GitHub.