JoinColumn и JoinTable
Обе аннотации описывают физическое хранение связи.
@JoinColumn
Указывает столбец внешнего ключа на владеющей стороне.
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "customer_id", nullable = false)
private Customer customer;name — столбец текущей таблицы, referencedColumnName — целевой столбец. Обычно ссылаться следует на первичный ключ, тогда второй параметр не нужен.
Для составного внешнего ключа используют @JoinColumns, и набор столбцов должен соответствовать целевому ключу.
@JoinTable
Описывает промежуточную таблицу:
@ManyToMany
@JoinTable(
name = "user_role",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "role_id")
)
private Set<Role> roles = new HashSet<>();У @ManyToMany таблица связи часто нужна. Если у связи появляются собственные поля — время назначения, статус, источник — её лучше превратить в отдельную entity, а не держать «чистый» many-to-many.
Владеющая сторона
Именно владелец записывает внешний ключ или строки join table. Изменение только коллекции на стороне mappedBy не гарантирует изменения БД. Удобно иметь метод, который обновляет обе стороны.
Вопросы для повторения
- Где находится
@JoinColumnу@ManyToOne? Обычно на стороне «многие», где физически хранится внешний ключ. - Что означает
mappedBy? Имя Java-поля владельца на другой стороне, а не имя столбца. - Когда many-to-many становится сущностью? Когда у отношения есть собственные атрибуты или жизненный цикл.
- Заменяет ли
nullable=falseвнешний ключ БД? Нет, схема должна содержать реальное ограничение.
Связано: Связи таблиц, Как смапить составной ключ, Fetch type Hibernate.