Связи (OneToMany)
JPA умеет автоматически связывать сущности так же, как JOIN связывает таблицы (см. тему «JOIN»), только на уровне Java-объектов.
@OneToMany/@ManyToOne — один пользователь имеет много заказов:
@Entity
class User {
@Id @GeneratedValue
private Long id;
@OneToMany(mappedBy = "user") // "один ко многим": у User много Order
private List<Order> orders;
}
@Entity
class Order {
@Id @GeneratedValue
private Long id;
@ManyToOne // "многие к одному": у Order один User
@JoinColumn(name = "user_id") // имя столбца внешнего ключа
private User user;
}
mappedBy указывает, что владелец связи (та сторона, где реально хранится внешний ключ в БД) — это Order.user, а User.orders — лишь “обратная сторона” для удобства навигации в коде.
Копнуть глубже
Все четыре вида связей:
| Аннотация | Смысл | Пример |
|---|---|---|
@OneToOne | один к одному | User ↔ Passport |
@OneToMany | один ко многим | User → много Order |
@ManyToOne | многие к одному | много Order → один User |
@ManyToMany | многие ко многим | Student ↔ много Course |
@ManyToMany требует промежуточную таблицу в базе (join table), которую JPA создаёт автоматически:
@ManyToMany
@JoinTable(name = "student_course",
joinColumns = @JoinColumn(name = "student_id"),
inverseJoinColumns = @JoinColumn(name = "course_id"))
private List<Course> courses;
Двусторонние связи требуют дисциплины. Если добавляешь Order пользователю, нужно обновить обе стороны связи вручную (user.getOrders().add(order); order.setUser(user);) — JPA не делает это автоматически, иначе объекты в памяти и состояние в базе могут разойтись.
• все четыре вида связей и почему двусторонние связи нужно обновлять с обеих сторон (если дошёл до 2-го слоя).