Рис. 5.8. Связь с использованием столбца соединения
Есть и второй способ моделирования — с применением таблицы соединения. В таблице CUSTOMER, показанной на рис. 5.9, больше нет внешнего ключа ADDRESS. Для размещения информации о связи с сохранением внешних ключей была создана промежуточная таблица.
Рис. 5.9. Связь с использованием таблицы соединения
Вы не стали бы использовать таблицу соединения для представления связи «один к одному», поскольку это могло бы отрицательно сказаться на производительности (вам всегда будет нужен доступ к третьей таблице для получения адреса клиента). Таблицы соединения обычно применяются при наличии кардинальностей «один ко многим» или «многие ко многим». Как вы увидите в следующем разделе, JPA использует два режима для отображения объектных ассоциаций.
Связи между сущностями
Теперь вернемся к JPA. Большинству сущностей необходима возможность ссылаться на другие сущности или иметь связи с ними. Именно это приводит к созданию графов доменной модели, распространенных в сфере бизнес-приложений. JPA позволяет отображать ассоциации, благодаря чему одна сущность может быть связана с другой в реляционной модели. Как это имеет место в случае с аннотациями элементарного отображения, которые вы видели ранее, JPA задействует конфигурацию в порядке исключения, когда речь идет об ассоциациях. JPA предусматривает используемый по умолчанию способ сохранения связей, однако если он окажется неподходящим для вашей модели базы данных, в вашем распоряжении есть несколько аннотаций, которые вы сможете использовать для настройки отображения.
Между двумя сущностями могут быть отношения «один к одному», «один ко многим», «многие к одному» или «многие ко многим». Каждое соответствующее отображение именуется согласно типу связи источника и цели: аннотации @OneToOne, @OneToMany, @ManyToOne или @ManyToMany. Каждая аннотация может быть использована однонаправленным или двунаправленным путем. В табл. 5.1 приведены все возможные комбинации типов связи и направлений.
Тип связи | Направление |
---|---|
«Один к одному» | Однонаправленный подход |
«Один к одному» | Двунаправленный подход |
«Один ко многим» | Однонаправленный подход |
«Многие к одному»/«один ко многим» | Двунаправленный подход |
«Многие к одному» | Однонаправленный подход |
«Многие ко многим» | Однонаправленный подход |
«Многие ко многим» | Двунаправленный подход |
Вы увидите, что названные подходы являются повторяющимися концепциями, которые применимы одинаковым образом ко всем типам связи. Далее вы узнаете, в чем заключается разница между однонаправленными и двунаправленными связями, а затем реализуете некоторые из соответствующих комбинаций. Я не стану подробно разбирать весь перечень комбинаций, а сосредоточусь на одном подмножестве. Объяснение всех комбинаций было бы повторением одного и того же. Важно, чтобы вы поняли, как отображать отношение и направление в связях.
С точки зрения объектного моделирования связь между классами естественна. При однонаправленной ассоциации объект А указывает только на объект В; при двунаправленной ассоциации оба объекта ссылаются друг на друга. Однако потребуется приложить усилия, когда речь зайдет об отображении двунаправленной связи в реляционную базу данных, как показано в следующем примере, включающем клиента, у которого имеется домашний адрес.
При однонаправленной связи у сущности Customer имеется атрибут типа Address (рис. 5.10). Эта связь является однонаправленной и предполагает навигацию от одной стороны к другой. Customer в данном случае называется владельцем связи. В контексте базы данных это означает, что таблица CUSTOMER будет располагать внешним ключом (столбцом соединения), указывающим на ADDRESS, а если вы будете владеть связью, то сможете настроить отображение этой связи. Например, если вам потребуется изменить имя внешнего ключа, отображение будет выполнено в сущности Customer (то есть владельце).
Рис. 5.10. Однонаправленная ассоциация между Customer и Address
Как уже отмечалось, связи также могут быть двунаправленными. Чтобы иметь возможность осуществлять навигацию между Address и Customer, вам потребуется преобразовать однонаправленную связь в двунаправленную, добавив атрибут Customer в сущность Address (рис. 5.11). Обратите внимание, что на UML-диаграммах классов не приводятся атрибуты, представляющие связь.
Рис. 5.11. Двунаправленная ассоциация между Customer и Address