Почему необходимо понятие «владеющая сторона»:
Идея владения стороной двунаправленного отношения исходит из того факта, что в реляционных базах данных нет двунаправленных отношений, как в случае объектов. В базах данных у нас только однонаправленные отношения - внешние ключи.
В чем причина названия «владеющая сторона»?
Собственная сторона отношения, отслеживаемого Hibernate, является стороной отношения, которой принадлежит внешний ключ в базе данных.
Какую проблему решает понятие владения стороной?
Возьмем пример двух сущностей, сопоставленных без , объявляющих собственную сторону:
@Entity
@Table(name="PERSONS")
public class Person {
@OneToMany
private List<IdDocument> idDocuments;
}
@Entity
@Table(name="ID_DOCUMENTS")
public class IdDocument {
@ManyToOne
private Person person;
}
С точки зрения ОО это отображение определяет не одно двунаправленное отношение, а два отдельных однонаправленных отношения.
При сопоставлении будут созданы не только таблицы PERSONS
и ID_DOCUMENTS
, но также будет создана третья таблица ассоциаций PERSONS_ID_DOCUMENTS
:
CREATE TABLE PERSONS_ID_DOCUMENTS
(
persons_id bigint NOT NULL,
id_documents_id bigint NOT NULL,
CONSTRAINT fk_persons FOREIGN KEY (persons_id) REFERENCES persons (id),
CONSTRAINT fk_docs FOREIGN KEY (id_documents_id) REFERENCES id_documents (id),
CONSTRAINT pk UNIQUE (id_documents_id)
)
Обратите внимание на первичный ключ pk
только на ID_DOCUMENTS
. В этом случае Hibernate отслеживает обе стороны отношения независимо: если вы добавляете документ в отношение Person.idDocuments
, он вставляет запись в таблицу ассоциации PERSON_ID_DOCUMENTS
.
С другой стороны, если мы вызываем idDocument.setPerson(person)
, мы меняем внешний ключ person_id в таблице ID_DOCUMENTS
. Hibernate создает два однонаправленных отношения (внешнего ключа) в базе данных для реализации one двунаправленного отношения объекта.
Как понятие «сторона владения» решает проблему:
Во многих случаях нам нужен только внешний ключ в таблице ID_DOCUMENTS
в направлении PERSONS
и дополнительная таблица ассоциации.
Чтобы решить эту проблему, нам нужно настроить Hibernate, чтобы перестать отслеживать изменения в отношении Person.idDocuments
. Hibernate должен отслеживать только другую сторону отношения IdDocument.person
, и для этого мы добавляем mappedBy :
@OneToMany(mappedBy="person")
private List<IdDocument> idDocuments;
Что значит mappedBy?
Это означает что-то вроде: "модификации на этой стороне отношения уже Mapped By
другая сторона отношения IdDocument.person, поэтому нет необходимости
отследите это здесь отдельно в дополнительной таблице. "
Есть ли какие-либо GOTCHA, последствия?
Использование mappedBy . Если мы вызовем только person.getDocuments().add(document)
, внешний ключ в ID_DOCUMENTS
будет НЕ связан с новым документом, поскольку это не является владельцем / отслеженным сторона отношения!
Чтобы связать документ с новым человеком, вам необходимо явно вызвать document.setPerson(person)
, потому что это сторона-владелец отношения.
При использовании mappedBy разработчик обязан знать, что является владельцем, и обновлять правильную сторону отношения, чтобы инициировать сохранение нового отношения в базе данных.