День 2. Маппинг ассоциаций в hibernate

Предыдущие материалы
И так, мы сделали маппинг для одного класса. Давайте немного расширим его, добавив несколько ассоциаций между классами. Мы добавим людей в приложение и сохраним список событий, в котором они участвуют
Маппинг класса Person
И так, класс Person выглядит следующим образом:
Создадим для него маппинг в src/main/resources/org/hibernate/tutorial/domain/Person.hbm.xml
И, наконец, добавим новый маппинг в конфигурацию Hibernate:
Теперь создадим ассоциацию между этими двумя сущностями. Люди (Persons) могут участвовать в событиях, а события могут иметь участников.
Однонаправленная ассоциация, основанная на Set
Если мы добавим коллекцию событий в класс Person, то сможем иметь доступ к событиям для определенного человека без выполнения дополнительных запросов, а через Person#getEvents. Ассоциации с множественными значениями представлены в Hibernate коллекциями из Java Collection Framework; в нашем примере мы выбрали java.util.Set, поскольку коллекция не будет содержать дубликатов, а порядок элементов не критичен для наших примеров:
Перед тем, как задавать маппинг для этой ассоциации, рассмотрим эту связь с другой стороны. Мы можем хранить однонаправленность или создать еще одну коллекцию в классе Event, если захотим иметь возможность навигации по элементам с обоих сторон. Вы всегда можете выполнить явный запрос для получения определенного события. Для доступа с обоих сторон, выберем ассоциацию many-to-many. И так, маппинг:
Hibernate поддерживает широкий диапазон коллекций для маппинга, но set - наиболее часто используемый. Для ассоциаций many-to-many необходима таблица ассоциаций. Каждый рядок в такой таблице представляет связь между person и event. Имя таблицы задается с использованием атрибута table в элементе set. Имя колонки с идентификатором для стороны person определяется элементом key, а имя колонки со стороны event определяется атрибутом column элемента many-to-many. Также, необходимо указать хибернейту на класс объектов в коллекции.
Схема базы данных для маппингов выглядит так:

Работа с ассоциацией
Сейчас мы свяжем немного людей с событиями в новом методе класса EventManager:
После загрузки Person и Event, просто изменяем коллекцию с использованием стандартных методов коллекции. Фактически, мы работаем с объектами без намека на то, что эти операции переводятся в SQL. Как Вы заметили, нет явных вызовов update(), save(). Хибернейт автоматически обнаруживает тот факт. что коллекции были модифицированы и нуждаются в обновлении. Этот механизм называется automatic dirty checking. Мы можем также попробовать его в действии посредством изменения имени или даты в объекте. Пока они в персистентном состоянии, то есть привязаны к определенному объекту сессии org.hibernate.Session, хибернейт наблюдает за всеми изменениями и генерирует SQL. Процесс синхронизации состояния объектов в памяти с базой данных, обычно происходит в момент завершения работы сессии, обычно это называется flusing или сливание. В нашем коде, сессия заканчивается комитом или откатом транзакции.
Мы можем загрузить person или event различными методами. Можно также модифицировать объект вне org.hibernate.Session, когда он не находится в персистентном состоянии (если он до этого был уже персистентным, тогда его состояние называется detached).
Посмотрим, как происходит модификация коллекции вне сессии:
Заменим предыдущий метод на вот этот:
Вызов метода update снова переводит объект в состояние персистивности, связывая его с новой единицей работы, поэтому любые модификации, проделанные над объектом, могут быть сохранены в базу данных.
В этом примере не много пользы, но он показывает важную концепцию, которую можно применить в своем проекте. Закончим наше упражнение добавлением нового действия в main метод класса EventManager и вызовем его из командной строки.
Если Вам необходимы идентификаторы person и event - то метод save() возвратит их. Немного поменяем существующий else if в main методе:
также изменим метод createAndStoreEvent, чтобы он возвращал id.
Коллекции значений
Добавим коллекцию email адресов в класс Person. Она будет представлена как java.util.Set со значениями java.lang.String:
И добавим соответствующий маппинг в Person.hbm.xml:
Разница по сравнению с предыдущим маппингом состоит в использовании части element, которая сообщает хибернейту о том, что коллекция не содержит ссылок на другие сущности. Атрибут table в элементе set определяет имя таблицы для коллекции.
Атрибут column в элементе element определяет имя колонки, в которой будут храниться значения адресов.
Вот обновленная схема:

Мы можем видеть, что первичный ключ коллекции, на самом деле, представляет из себя составной ключ, который использует обе колонки. Теперь попробуем добавить элементы в коллекцию также, как мы это делали раньше, связывая людей с событиями.
На этот раз, мы не использовали fetch запрос для инициализации коллекции.
Двунаправленные ассоциации
Сейчас добавим маппинг для двунаправленной ассоциации (bi-directional association). Сделаем ассоциацию между person и event для работы с обоих сторон. Схема базы не меняется.
Сперва, добавим коллекцию участников в класс Event:
Теперь добавим маппинг в Event.hbm.xml:
Заметьте, что имена колонок в key и many-to-many поменялись местами в обоих документах. Наиболее важное дополнение здесь - это атрибут inverse="true" в элементе set.
Оно сигнализирует о том, что хибернейт должен взять другую сторону, класс Person, когда ему необходимо найти информацию о связях. Намного проще будет понять этот отстой один раз увидев двунаправленную связь между двумя сущностями.
Работа с двунаправленными связями
Во-первых, запомните, что Hibnernate не затрагивает симантику Java. Как мы создаем связь между классами Person и Event в однонаправленном примере? Мы добавляем объект Event в коллекцию ссылок на события в классе Person. Если мы хотим сделать эту связь двунаправленной, необходимо сделать то же самое на стороне событий, добавив ссылку person на коллекцию в Event. Этот процесс установки связей на обоих сторонах является необходимым при работе с двунаправленными связями.
Материалы, которые могут вас заинтересовать
- День 1. Минимальный проект с использованием java + hibernate + mysql
- Почему локальные вложенные классы имеют доступ только к final переменным?
- Java .class file version или под какую джаву скомпилирован класс?
- Играем в компилятор. Часть 3.
- Elementary Java.
- Играем в компилятор. Часть 2.
- Играем в компилятор.
- Elementary Java.
- Когда есть свободная минутка. Java задача.







хм…ну это памойму уже крайность…
Что Вы имеете ввиду?
Дружище, когда используешь set в связи один-ко-многим или многие-ко-многим надо перекрывать методы equals и hashCode
Благодарю за совет. Вы правы.
Кстати, hibernate при старте сам выдаст жирный варнинг о том, что equals и hashCode не переопределены.
Но, согласитесь, это не критично.
Отправить комментарий