Создание связей типа многие-к-одному между классами-сущностями с помощью аннотации @ManyToOne в Hibernate

Создание простых связей типа многие-к-одному в моделях предметной области полностью соответствует взаимоотношению таблиц в БД. Строки одной из таблиц содержат внешний ключ, ссылающийся на строку другой таблицы. При этом та таблица, на которую ссылаются, об этом «не знает». Во многих случаях в модели предметной области воспроизведение подобных отношений между классами-сущностями оказывается достаточным.

Подготовка

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

Код

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

Класс Person не ссылается ни на какие другие классы предметной области. И не содержит никаких сведений о том, ссылается ли какой-то класс на него.

Создадим следующий класс предметной области, ссылающийся на предыдущий:

Аннотация @ManyToOne над полем Person person указывает Hibernate’у создать связь вида многие-к-одному между сущностями Address и Person. С точки зрения БД, в таблице ADDRESS будет создано поле с внешним ключом под названием PERSON_ID (так как мы ссылаемся на таблицу PERSON, в которой первичный ключ — колонка ID). Аннотация @ManyToOne — единственное, что требуется для установления связи многие-к-одному.

Использование аннотации @JoinColumn носит необязательный характер. Но в ней можно переопределить название колонки внешнего ключа (мы оставили его таким же, как если бы Hibernate создал его автоматически), а также добавить этой колонке некоторые ограничения. В нашем примере мы делаем её NOT NULL колонкой, из-за чего связь между адресом и персоной становится обязательной (но могла бы таковой и не быть).

Создадим репозиторий для сущности Person:

Создадим репозиторий для сущности Address:

Напишем тестовый метод, который продемонстрирует работу настроек:

Мы создали один объект irina типа Person и список из двух объектов типа Address. Создавая объекты Address, мы заполнили поле person ссылкой на объект irina. Затем сохранили все созданные объекты. Так как и Person, и Address являются классами-сущностями, то они сами управляют своим жизненным циклом.

Затем мы вызываем метод addressRepository.findByPerson(irina), с помощью которого ищем все строки таблицы ADDRESS, соответствующие созданному ранее объекту irina. И действительно, такие строки находятся, что показывает нам, что Hibernate правильно установил связи многие-к-одному между классами Address и Person — в БД на одну строку таблицы PERSON ссылается несколько строк таблицы ADDRESS. И имея данные строки таблицы PERSON можно найти соответствующие строки таблицы ADDRESS.