Автор оригинала: Vlad Mihalcea.
Вступление
В этой статье мы рассмотрим, как вы можете изменить имя столбца @OneToOne
общий первичный ключ при использовании JPA и Hibernate. Это была повторяющаяся тема, когда отвечал на вопросы о спящем режиме или во время моего Высокопроизводительного обучения сохраняемости Java .
Как уже объяснялось ранее , связь таблиц базы данных “один к одному” требует, чтобы Первичный ключ был общим для родительской и дочерних таблиц.
К сожалению, простое добавление аннотации JPA @OneToOne
в дочернюю сущность не отображает истинную связь таблицы “один к одному”, поскольку будет использоваться отдельный столбец внешнего ключа. Только при добавлении аннотации @MapsId
ассоциация JPA “один к одному” сопоставляется с реальным отношением таблицы “один к одному”.
Как изменить @OneToOne имя столбца общего первичного ключа с помощью JPA и гибернации @vlad_mihalcea https://t.co/BoQsxJ6Lvm pic.twitter.com/kP5hgBRw1b
Модель предметной области
Давайте предположим, что мы используем следующие Сообщения
и Сведения о сообщениях
сущности:
Сущность Post
является родительской, в то время как Сведения о записи
является дочерней сущностью, и связанный с ней Первичный ключ также является внешним ключом к Первичному ключу родительской таблицы.
Объект Post
довольно просто сопоставить, так как он не содержит никаких ассоциаций:
@Entity(name = "Post") @Table(name = "post") public class Post { @Id @GeneratedValue private Long id; private String title; //Getters and setters omitted for brevity }
Сведения о публикации
могут быть сопоставлены следующим образом:
@Entity(name = "PostDetails") @Table(name = "post_details") public class PostDetails { @Id private Long id; @Column(name = "created_on") private Date createdOn; @Column(name = "created_by") private String createdBy; @OneToOne(fetch = FetchType.LAZY) @MapsId private Post post; public PostDetails() {} public PostDetails(String createdBy) { createdOn = new Date(); this.createdBy = createdBy; } //Getters and setters omitted for brevity }
Обратите внимание, что мы используем FetchType.ЛЕНИВЫЙ
явно, так как по умолчанию JPA использует Fetchtype.ЖАЖДЕТ
для @OneToOne
и @ManyToOne
ассоциаций, и это очень плохо сказывается на производительности .
При создании схемы с помощью инструмента hbm2ddl или при создании схемы вручную и управлении ею с помощью Flyway Hibernate ожидает следующую структуру таблиц базы данных:
Обратите внимание, что имя столбца первичного ключа называется post_id
в таблице post_details
, и это не очень приятно, так как имя столбца первичного ключа называется id
в таблице post
.
@JoinColumn спешит на помощь
Чтобы устранить эту проблему, нам просто нужно добавить @JoinColumn
аннотацию к @OneToOne
ассоциации в Сведения о публикации
сущности:
@OneToOne @MapsId @JoinColumn(name = "id") private Post post;
Таким образом, Hibernate либо создаст, либо ожидает следующие таблицы базы данных:
Потрясающе, правда?
Вывод
Немного жаль, что по умолчанию в аннотации @MapsId
не используется имя идентификатора сущности, соответствующее столбцу первичного ключа базовой таблицы. Однако использование аннотации @JoinColumn
является простым способом устранения этой проблемы.