«1. Обзор

Агрегатные функции Hibernate вычисляют окончательный результат, используя значения свойств всех объектов, удовлетворяющих заданным критериям запроса.

Язык запросов Hibernate (HQL) поддерживает различные агрегатные функции — min(), max(), sum(), avg() и count() в операторе SELECT. Как и любое другое ключевое слово SQL, использование этих функций не зависит от регистра.

В этом кратком руководстве мы рассмотрим, как их использовать. Обратите внимание, что в приведенных ниже примерах мы используем либо примитивные типы, либо типы-оболочки для хранения результатов агрегатных функций. HQL поддерживает оба варианта, так что нужно выбирать, какой из них использовать.

2. Первоначальная настройка

Давайте начнем с определения объекта Student:

@Entity
public class Student {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private long studentId;

    private String name;

    private int age;

    // constructor, getters and setters
}

И заполним нашу базу данных некоторыми студентами:

public class AggregateFunctionsIntegrationTest {

    private static Session session;
    private static Transaction transaction;

    @BeforeClass
    public static final void setup() throws HibernateException, IOException {
        session = HibernateUtil.getSessionFactory()
          .openSession();
        transaction = session.beginTransaction();

        session.save(new Student("Jonas", 22, 12f));
        session.save(new Student("Sally", 20, 34f));
        session.save(new Student("Simon", 25, 45f));
        session.save(new Student("Raven", 21, 43f));
        session.save(new Student("Sam", 23, 33f));

    }

}

Обратите внимание, что наше поле studentId было заполнено с помощью генерации ПОСЛЕДОВАТЕЛЬНОСТИ стратегия.

Мы можем узнать больше об этом в нашем руководстве по стратегиям генерации идентификаторов Hibernate.

3. min()

Теперь предположим, что мы хотим найти минимальный возраст среди всех студентов, хранящихся в нашей таблице Student. Мы можем легко сделать это с помощью функции min():

@Test
public void whenMinAge_ThenReturnValue() {
    int minAge = (int) session.createQuery("SELECT min(age) from Student")
      .getSingleResult();
    assertThat(minAge).isEqualTo(20);
}

Метод getSingleResult() возвращает тип объекта. Итак, мы понизили вывод до int.

4. max()

Подобно функции min(), у нас есть функция max():

@Test
public void whenMaxAge_ThenReturnValue() {
    int maxAge = (int) session.createQuery("SELECT max(age) from Student")
      .getSingleResult();
    assertThat(maxAge).isEqualTo(25);
}

Здесь снова результат понижается до типа int.

Тип возвращаемого значения функций min() и max() зависит от поля в контексте. Для нас он возвращает целое число, так как возраст студента является атрибутом типа int.

5. sum()

Мы можем использовать функцию sum(), чтобы найти сумму всех возрастов:

@Test
public void whenSumOfAllAges_ThenReturnValue() {
    Long sumOfAllAges = (Long) session.createQuery("SELECT sum(age) from Student")
      .getSingleResult();
    assertThat(sumOfAllAges).isEqualTo(111);
}

В зависимости от типа данных поля функция sum() возвращает либо Long, либо двойной.

6. avg()

Точно так же мы можем использовать функцию avg() для определения среднего возраста:

@Test
public void whenAverageAge_ThenReturnValue() {
    Double avgAge = (Double) session.createQuery("SELECT avg(age) from Student")
      .getSingleResult();
    assertThat(avgAge).isEqualTo(22.2);
}

Функция avg() всегда возвращает значение типа Double.

7. count()

Как и в родном SQL, HQL также предоставляет функцию count(). Найдем количество записей в нашей таблице Student:

@Test
public void whenCountAll_ThenReturnValue() {
    Long totalStudents = (Long) session.createQuery("SELECT count(*) from Student")
      .getSingleResult();
    assertThat(totalStudents).isEqualTo(5);
}

Функция count() возвращает тип Long.

Мы можем использовать любой из доступных вариантов функции count(): count(*), count(…), count(distinct…) или count(all…). Каждый из них семантически эквивалентен своему собственному аналогу SQL.

8. Заключение

В этом уроке мы кратко рассмотрели типы агрегатных функций, доступных в Hibernate. Агрегатные функции Hibernate аналогичны тем, которые доступны в простом старом SQL.

Как обычно, полный исходный код доступен на GitHub.