В контексте Java-кода и аннотаций это аналогично наличию двух отдельных отображений «один к одному», по одному в каждом направлении. Вы можете представлять себе двунаправленную связь как пару однонаправленных связей, идущих соответственно туда и обратно (рис. 5.12).
Рис. 5.12. Двунаправленная ассоциация, представленная двумя стрелками
Как осуществляется отображение пары однонаправленных связей? Кто является владельцем двунаправленной связи? Кто владеет информацией об отображении столбца соединения или таблицы соединения? Если у однонаправленных связей есть владеющая сторона, то у двунаправленных связей есть как владеющая, так и противоположная сторона, которая должна быть указана явным образом с помощью элемента mappedBy аннотаций @OneToOne, @OneToMany и @ManyToMany. Элемент mappedBy идентифицирует атрибут, который владеет связью и необходим для двунаправленных связей.
Для пояснения сравним Java-код (с одной стороны) и отображение базы данных (с другой стороны). Как вы можете видеть в левой части рис. 5.13, обе сущности указывают друг на друга с помощью атрибутов: у Customer имеется атрибут, аннотированный с использованием @OneToOne, а у сущности Address — атрибут Customer, тоже снабженный аннотацией. В правой части располагается отображение базы данных, где показаны таблицы CUSTOMER и ADDRESS. CUSTOMER является владельцем связи, поскольку содержит внешний ключ ADDRESS.
Рис. 5.13. Код Customer и Address наряду с отображением базы данных
На рис. 5.13 в аннотации @OneToOne сущности Address используется элемент mappedBy. Address в данном случае именуется противоположным владельцем связи, поскольку обладает элементом mappedBy. Элемент mappedBy говорит о том, что столбец соединения (address) указан на другом конце связи. Кроме того, на другом конце связи сущность Customer определяет столбец соединения путем использования аннотации @JoinColumn и переименовывает внешний ключ в address_fk. Сущность Customer представляет собой владеющую сторону связи и, как владелец, должна определять отображение столбца соединения. Address выступает в качестве противоположной стороны связи, где таблица владеющей сущности содержит внешний ключ (таблица CUSTOMER включает столбец ADDRESS_FK).
Элемент mappedBy может присутствовать в аннотациях @OneToOne, @OneToMany и @ManyToMany, но не в @ManyToOne. Атрибут mappedBy не может быть сразу на обеих сторонах двунаправленной ассоциации. Было бы также неправильно, если бы его не было ни на одной из сторон, поскольку поставщик воспринимал бы все это как две независимые однонаправленные связи. Это подразумевало бы, что каждая из сторон является владельцем и может определять столбец соединения.
Если вы знакомы с более ранними версиями Hibernate, то можете представлять себе JPA-параметр mappedBy как эквивалент Hibernate-атрибута inverse.
Однонаправленная связь «один к одному» между сущностями имеет ссылку кардинальности 1, которая досягаема только в одном направлении. Обратившись к примеру клиента и его домашнего адреса, предположим, что у него имеется только один домашний адрес (кардинальность 1). Важно выполнить навигацию от Customer (источник) по направлению к Address (цель), чтобы узнать, где клиент живет. Однако по некоторым причинам при нашей модели, показанной на рис. 5.14, вам не потребуется возможность навигации в противоположном направлении (например, вам не будет нужно знать, какой клиент живет по определенному адресу).
Рис. 5.14. У одного клиента имеется один домашний адрес
В Java однонаправленная связь означает, что у Customer будет иметься атрибут Address (листинг 5.35), однако у Address не будет атрибута Customer (листинг 5.36).
@Entity
public class Customer {
··@Id @GeneratedValue
··private Long id;
··private String firstName;
··private String lastName;
··private String email;
··private String phoneNumber;
··private Address address;
··// Конструкторы, геттеры, сеттеры
}
@Entity
public class Address {
··@Id @GeneratedValue
··private Long id;
··private String street1;
··private String street2;
··private String city;
··private String state;
··private String zipcode;
··private String country;
··// Конструкторы, геттеры, сеттеры
}