Связи между таблицами
Обычно при создании проектов необходимо связывать таблицы между собой, это нужно для логической связи объектов между собой. Так как реляционная база данных представляет собой множество взаимосвязанных таблиц, то необходимо уделить отдельное внимание описанию отношений между сущностями с помощью технологии hibernate. Всего существует три основных типа связи: one-to- one, one-to-many, many-to-one; существует также связь many-to-many, но она может быть решена как специальной аннотацией @many-to- many, так и промежуточной таблицей.
Связь many-to-one
Разберем пример. Есть сущность people, которая связана с phone, то есть две таблицы: люди и телефоны. У одного человека может быть несколько телефонов, но не наоборот. Для этого мы создаем связь many-to-one, при этом в таблице phone появится новое поле, ссылающееся на элемент таблицы people, в нем будет храниться идентификатор. Класс people был уже описан ранее, в данном случае он остается неизменным. Класс phone выглядит следующим образом:
- 1. (©Entity
- 2. (©Table (name = "phones")
- 3. public class Phone {
- 4. @Id
- 5. (©GeneratedValue (strategy = GenerationType.IDENTITY)
- 6. (©Column (name = "id")
- 7. private int id;
- 8. (©Column (name = "number")
- 9. private String number;
- 10. (©ManyToOne (targetEntity = People.class, fetch = FetchType.
LAZY)
- 11. (©JoinColumn (name = "id_poeple")
- 12. private People people;
- 13. ... (описываем геттеры и сеттер)
- 14. }
Аннотация (©ManyToOne позволяет создать связь между двумя таблицами, в базе данных данная связь будет выглядеть, как показано на рис. 2.3. Также при использовании связи many-to-one автоматически создается вторичный ключ.

Рис. 2.3. Связь таблиц many-to-one
Свойство targetEntity указывает, с какой сущностью будет происходить соединение по внешнему ключу.
Свойство fetch (очень важное свойство) может иметь два состояния: LAZY или EAGER — по умолчанию это EAGER. В случае если параметром будет выступать EAGER, связанный элемент будет сразу же подгружаться автоматически. LAZY — пока не обратятся к элементу people, данные не будут загружены.
Ниже показано, как будут формироваться запросы в зависимости от установленного свойства fetch.
При запросе к БД:
- 1. Phone phone = (Phone) session.createCriteria (Phone.class).add (Restrictions.eq ("id", l)).uniqueResult ();
- 2. People people = phone.getPeople ();
Простой запрос на получение элемента таблицы телефон и связанного с ним человека.
fetch = FetchType.LAZY
При выполнении первой строчки будет сформирован запрос на получение данных только о таблице Phone, и только когда идет обращение к связанному объекту People, формируется новый запрос.
- 1. Hibernate: select this_.id as idl_l_0_, this_.number as number2_l_0_, this_.id_poeple as id_poepl3_l_0_ from phones this_ where this_.id=?
- 2. Hibernate: select peopleO_.id as idl_0_0_, peopleO_.firstName as firstNam2_0_0_, peopleO_.lastName as lastName3_0_0_, peopleO_.middleName as middleNa4_0_0_, peopleO_.year as year5_0_0_ from people peopleO_ where peopleO_.id = ?
При этом важно понимать, что если сессия будет закрыта, а после этого будет обращение к объекту, который еще не подгружался, то произойдет ошибка. Для инициализации можно применить следующий код:
Hibernate.initialize (phone.getPeopleO);
fetch = FetchType.EAGER
При выполнении первой строчки кода будет формироваться один большой запрос, который автоматически будет подгружать связанного с данным телефоном человека.
Пример сформированного запроса:
Hibernate: select this_.id as idl_l_l_, this_.number as number2_l_l_, this_.id_poeple as id_poepl3_l_l_, people2_.id as idl_0_0_, people2_. firstName as firstNam2_0_0_, people2_.lastName as lastName3_0_0_, people2_.middleName as middleNa4_0_0_, people2_.year as year5_0_0_ from phones this_ left outer join people people2_ on this_.id_ poeple=people2_.id where this_.id = ?
Аннотация @JoinColumn в данном случае является не обязательной, она просто содержит параметр, в котором можно указать название колонки.
Связь one-to-many.
Часто требуется делать и обратную связь, то есть, имея объект people, получать список связанных с ним телефонов.
- 1. @Entity
- 2. @Table (name = "people")
- 3. public class People {
- 4. ...
- 5. @OneToMany (targetEntity = Phone.class, mappedBy = "people", fetch = FetchType.LAZY)
- 6. private List
phones; - 7. ...
- 8. }
Аннотация @OneToMany позволяет осуществить эту мнимую связь, которая обеспечивается hibernate, но не БД. Параметр targetEntity указывает, с какой сущностью идет связь. В параметре mappedBy прописывается имя связующего поля с аннотацией @МапуТоОпе, то есть его имя people. Параметр fetch был ранее описан, в данном случае он играет ту же самую функцию.