Что является «стороной-владельцем» в сопоставлении ORM?

129

Что именно означает сторона собственника ? Как можно объяснить некоторые примеры сопоставления ( один ко многим, один к одному, многие к одному )?

Следующий текст - это отрывок из описания @OneToOne в документации Java EE 6. Вы можете увидеть в этом сторону, владеющую концепцией .

Определяет однозначную связь с другой сущностью, имеющую однозначную множественность. Обычно нет необходимости явно указывать связанный целевой объект, поскольку он обычно может быть выведен из типа объекта, на который имеется ссылка. Если отношение является двунаправленным, не владеющая сторона должна использовать элемент mappedBy аннотации OneToOne, чтобы указать поле отношения или свойство стороны-владельца.

Просто ученик
источник
5
Я был потерян, пока не прочитал это: javacodegeeks.com/2013/04/…
darga33
2
Таблица БД со столбцом внешнего ключа рассматривается как сторона-владелец. Таким образом, бизнес-объект, представляющий эту таблицу БД, является владельцем (стороной-владельцем) этого отношения. Не обязательно, но в большинстве случаев на стороне владельца будет аннотация @JoinColumn.
Diablo

Ответы:

202

Почему необходимо понятие стороны собственности:

Идея владения стороны двунаправленного отношения исходит из того факта, что в реляционных базах данных нет двунаправленных отношений, как в случае с объектами. В базах данных у нас только однонаправленные отношения - внешние ключи.

В чем причина названия «сторона собственника»?

Собственная сторона отношения, отслеживаемая 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 создает в базе данных два однонаправленных (внешних ключа) отношения, чтобы реализовать одно двунаправленного объектного отношения.

Как идея владения стороной решает проблему:

Много раз то , что мы хотим только внешний ключ на столе в ID_DOCUMENTSстороне PERSONSи дополнительная таблица ассоциации.

Чтобы решить эту проблему, нам нужно настроить Hibernate, чтобы перестать отслеживать изменения в отношении Person.idDocuments. Hibernate должен отслеживать только другую сторону отношения IdDocument.person, и для этого мы добавляем mappedBy :

@OneToMany(mappedBy="person")
private List<IdDocument>  idDocuments;

Что это значит mappedBy?

Это означает что - то вроде: «модификации на этой стороне отношений уже Подключенные К другой стороне отношений IdDocument.person, поэтому нет необходимости отслеживать его здесь отдельно в дополнительной таблице.»

Есть ли GOTCHA, последствия?

Использование mappedBy , если мы только называем person.getDocuments().add(document), внешний ключ в ID_DOCUMENTSбудет НЕ быть связаны с новым документом, поскольку это не владеющая / гусеничная стороны отношения!

Чтобы связать документ с новым человеком, вам нужно явно вызвать document.setPerson(person), потому что это сторона-владелец отношения .

При использовании mappedBy разработчик обязан знать, что является стороной-владельцем, и обновлять правильную сторону отношения, чтобы вызвать сохранение нового отношения в базе данных.

Угловой университет
источник
17
Лучший ответ, который я нахожу, объясняет Доктрину mappedBy + reverseBy.
Курт Чжун
1
Спасибо, что указали сопоставления и причину концепции.
Mohnish
1
Я не знаю, изменилось ли что-то, но в Hibernate 5.0.9.Final, если я "только вызываю person.getDocuments().add(document)", hibernate обновляет внешний ключ ID_DOCUMENTS.
K.Nicholas
1
@Karl Nicholas, привет, согласен с вами, у нас есть атрибут cascade в @OneToManyаннотации, который можно установить на PERSIST, в этом случае спящий режим сохранит все связанные объекты в БД. Кто-нибудь может прояснить это - почему автор говорит, что спящий режим не будет отслеживать изменения на стороне, не являющейся владельцем, но на самом деле спящий режим выполняет отслеживание?
Александр Папченко
3
cascade говорит провайдеру сохранять дочерние сущности, даже если родительская сущность не владеет ими, поэтому он эффективно изменяет правило. Если бы у вас был (или был) mappedBy = child.field и НЕ было каскада, то дочерние элементы списка не были бы сохранены. Кроме того, если у вас не было mappedBy И не было каскада, тогда отношениями владеет родительский элемент, и если вы поместите НОВЫХ дочерних элементов в список, а затем сохраните родительский элемент, он выдаст исключение, потому что новые идентификаторы дочерних элементов недоступны для быть сохраненным в таблице соединений. Надеюсь, это проясняет ситуацию ... :)
К.Николас
142

Вы можете представить, что сторона-владелец - это сущность, имеющая ссылку на другую. В вашем отрывке у вас отношения один на один. Поскольку это симметричный отношение, вы в конечном итоге получите то, что если объект A связан с объектом B, то верно и обратное.

Это означает, что сохранение в объекте A ссылки на объект B и сохранение в объекте B ссылки на объект A будет избыточным: вот почему вы выбираете, какой объект «владеет» другим, имеющим ссылку на него.

Когда у вас есть отношение «один ко многим», объекты, относящиеся к части «многие», будут являться стороной-владельцем, в противном случае вам пришлось бы хранить множество ссылок от одного объекта к множеству. Чтобы этого избежать, каждый объект во втором классе будет иметь указатель на единственный объект, на который они ссылаются (так что они являются стороной-владельцем).

Для отношения «многие ко многим», поскольку вам в любом случае потребуется отдельная таблица сопоставления, стороны-владельца не будет.

В заключение, сторона-владелец - это сущность, имеющая ссылку на другую.

разъем
источник
6
Благодарим Вас за разъяснения.
Просто ученик
2
может также помочь увидеть ниже мой ответ по причинам имен 'mappedBy' и 'owning side', что произойдет, если мы не определим владеющую сторону, GOTCHA, надеюсь, это поможет
Angular University
5
Что ж, я думаю, ответ в основном правильный. Но, по крайней мере, для Hibernate, даже отношения «многие ко многим» имеют свою сторону. Это, например, влияет на поведение обновления. Внимательно
изучите
11
Этот ответ больше сбивает с толку, чем помогает. Что хорошего в том, чтобы сказать, что «вы можете представить, что сторона-владелец - это сущность, имеющая ссылку на другую», когда в двунаправленных отношениях оба объекта Entity будут ссылаться друг на друга? Кроме того, выражение «для отношения« многие ко многим », поскольку вам в любом случае потребуется отдельная таблица сопоставления, не будет никакой стороны-владельца», это просто неверно: @ManyToManyотношения также имеют стороны-владельцы. Точно так же @OneToManyотношения могут использовать таблицы соединения, и вам все равно нужно указать сторону-владельца.
DavidS
5
По сути, это милый, приятный ответ, за который есть положительные голоса, потому что его легче понять, чем правду.
DavidS