Аннотация @JoinColumn указывает, что эта сущность является владельцем связи (то есть: соответствующая таблица имеет столбец с внешним ключом к таблице, на которую ссылается ссылка), тогда как атрибут mappedBy указывает, что сущность на этой стороне является обратной связи, а владелец находится в "другой" сущности. Это также означает, что вы можете получить доступ к другой таблице из класса, который вы аннотировали с помощью "mappedBy" (полностью двунаправленная связь).
В частности, для кода в вопросе правильные аннотации будут выглядеть следующим образом:
@JoinColumn может использоваться с обеих сторон связи. Вопрос был об использовании @JoinColumn на @OneToMany стороне (редкий случай). И дело здесь в физическом дублировании информации наряду с неоптимизированным SQL-запросом, который выдаст некоторые дополнительные UPDATE инструкции.
Поскольку в спецификации JPA двунаправленные отношения многие к одному (почти) всегда находятся на стороне владельца, ассоциация "один ко многим" аннотируется @OneToMany(mappedBy=...)
@Entity publicclassTroop { @OneToMany(mappedBy="troop") public Set<Soldier> getSoldiers() { ... }
Troop имеет двунаправленную связь "один ко многим" с Soldier через свойство troop . Вам не нужно (не должно) определять какое-либо физическое отображение на стороне mappedBy.
Чтобы сопоставить двунаправленный параметр "один ко многим" со стороной "один ко многим" в качестве стороны-владельца, вы должны удалить mappedBy элемент и установить для параметра "много" значение "один" @JoinColumn как insertable и updatable значение false. Это решение не оптимизировано и приведет к появлению некоторых дополнительных UPDATE инструкций.
@Entity publicclassTroop { @OneToMany @JoinColumn(name="troop_fk")//we need to duplicate the physical information public Set<Soldier> getSoldiers() { ... }
Если вы используете @OneToMany аннотацию с @JoinColumn, то у вас будет однонаправленная связь, подобная связи между родительским Post объектом и дочерним PostComment объектом на следующей диаграмме:
При использовании однонаправленной ассоциации "один ко многим" сопоставляет ассоциацию только родительская сторона.
В этом примере только Post объект будет определять @OneToMany ассоциацию с дочерним PostComment объектом:
Если вы используете @OneToMany с mappedBy набором атрибутов, у вас получается двунаправленная связь. В нашем случае как у Post объекта есть коллекция PostComment дочерних объектов, так и у дочернего PostComment объекта есть обратная ссылка на родительский Post объект, как показано на следующей диаграмме:
В PostComment сущности свойство post entity отображается следующим образом:
@ManyToOne(fetch = FetchType.LAZY) private Post post;
Причина, по которой мы явно устанавливаем для fetch атрибута значение FetchType.LAZY, заключается в том, что по умолчанию все @ManyToOne и @OneToOne ассоциации извлекаются быстро, что может вызвать N + 1 проблем с запросами.
В Post сущности comments ассоциация отображается следующим образом:
mappedBy Атрибут @OneToMany аннотации ссылается на post свойство дочерней PostComment сущности, и, таким образом, Hibernate знает, что двунаправленная связь контролируется @ManyToOne стороной, которая отвечает за управление значением столбца внешнего ключа, на котором основана эта табличная связь.
Для двунаправленной ассоциации вам также необходимо иметь два служебных метода, таких как addChild и removeChild:
Эти два метода гарантируют, что обе стороны двунаправленной ассоциации синхронизированы. Без синхронизации обоих концов Hibernate не гарантирует, что изменения состояния ассоциации будут распространяться на базу данных.
Какой из них выбрать?
Однонаправленная @OneToMany ассоциация работает не очень хорошо, поэтому вам следует избегать ее.
Вам лучше использовать двунаправленный @OneToMany который более эффективен.
Ответ 4
Я не согласен с принятым здесь ответом Оскара Лопеса. Этот ответ неточен!
Это НЕ @JoinColumn который указывает, что эта сущность является владельцем отношения. Вместо этого это @ManyToOne аннотация, которая делает это (в его примере).
Аннотации отношений, такие как @ManyToOne, @OneToMany и @ManyToMany, указывают JPA / Hibernate создать сопоставление. По умолчанию это делается с помощью отдельной таблицы соединений.
@JoinColumn
Цель @JoinColumn - создать объединенный столбец, если он еще не существует. Если это так, то эту аннотацию можно использовать для именования объединяемого столбца.
mappedBy
Цель MappedBy параметра - указать JPA: НЕ создавать другую таблицу объединения, поскольку связь уже сопоставляется противоположной сущности этой связи.
Помните: MappedBy это свойство аннотаций отношений, целью которого является создание механизма для связи двух сущностей, что по умолчанию они делают путем создания таблицы соединений. MappedBy останавливает этот процесс в одном направлении.
Объект, не использующий MappedBy, считается владельцем отношения, потому что механика сопоставления определяется внутри его класса посредством использования одной из трех аннотаций сопоставления для поля внешнего ключа. Это не только определяет характер сопоставления, но и инструктирует к созданию таблицы соединений. Кроме того, также существует возможность подавления таблицы объединения путем применения аннотации @JoinColumn к внешнему ключу, которая вместо этого сохраняет его внутри таблицы объекта-владельца.
Итак, вкратце: @JoinColumn либо создает новый объединяемый столбец, либо переименовывает существующий; в то время как MappedBy параметр работает совместно с аннотациями отношений другого (дочернего) класса, чтобы создать сопоставление либо через таблицу объединения, либо путем создания столбца внешнего ключа в связанной таблице объекта-владельца.
Чтобы проиллюстрировать, как MapppedBy работает, рассмотрим приведенный ниже код. Если бы MappedBy параметр нужно было удалить, то Hibernate фактически создал бы ДВЕ таблицы соединений! Почему? Поскольку в отношениях "многие ко многим" существует симметрия, а у Hibernate нет обоснования для выбора одного направления вместо другого.
Поэтому мы используем MappedBy, чтобы сообщить Hibernate, что мы выбрали другую сущность, чтобы диктовать отображение отношений между двумя сущностями.
Добавление @JoinColumn(name = "DriverID") в класс owner (см. Ниже) предотвратит создание таблицы соединений и вместо этого создаст столбец внешнего ключа DriverID в таблице Cars для построения сопоставления: