Создание производных полей в классах предметной области с помощью аннотации @Formula в Hibernate

Зачастую выборка из таблицы должна содержать не только колонки с данными, но и колонки с вычисляемыми (обычно с помощью функций и подзапросов) значениями. Это могут быть, например, средние, минимальные и максимальные величины. Если для таких случаев по тем или иным причинам в БД не созданы представления (view), то мы можем указать Hibernate’у усложнить запрос и выбрать дополнительные данные в выборку с помощью аннотации @Formula.

Создадим минимальное Spring Boot приложение с поддержкой JPA/Hibernate

Если в директории /src/main/resources нет файла application.properties, то создайте его там и добавьте в него следующую строчку:

Это позволит видеть в консоли SQL выражения, которые будет создавать Hibernate, выполняю свою работу.

Затем создадим класс предметной области следующего содержания:

В качестве параметра value в аннотацию @org.hibernate.annotations.Formula мы передаём фрагмент SQL, который соберёт данные для заполнения новой колонки average_age, которая будет сформирована только для этого запроса. Как видите, в производных полях можно использовать полноценные подзапросы SELECT.

Главное, что нужно учитывать при составлении подобных подзапросов, это то, что они пишутся на диалекте конкретной СУБД. Есть возможность использовать любые стоковые функции СУБД, но всё это может нанести ущерб переносимости.

Создадим репозиторий:

Создадим тест следующего содержания:

После запуска тест должен быть пройден. В случае, если тест падает, возможно стоит поэксперементировать с возрастами из-за возможных неточностей арифметики чисел с плавающей точкой (вероятность невелика, но всякое бывает).

В консоли можно будет увидеть следующий вывод работы Hibernate (может быть перемешан с выводом других систем программы):

В первых четырёх строках Hibernate запрашивает сиквенсы и делает вставки двух строк в таблицу. А в последней пятой строчке делает выборку. Причём третьей колонкой запрашивает наше производное значение.

Таким образом можно запрашивать различные производные значения. Но обычно стоит всё-таки держать в уме проблему переносимости и обходится только стандартными функциями.