Ответ
JPA (Hibernate как его реализация) определяет четыре основных типа связей между сущностями, которые отображаются на реляционные связи в БД.
1. Один-к-одному (@OneToOne)
Одна сущность связана ровно с одним экземпляром другой сущности.
@Entity
public class User {
@Id
private Long id;
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name = "profile_id") // Владелец связи, содержит внешний ключ
private UserProfile profile;
}
@Entity
public class UserProfile {
@Id
private Long id;
@OneToOne(mappedBy = "profile") // Обратная, невладеющая сторона
private User user;
}
- Использование: Профиль пользователя, паспортные данные.
- Важно: Обычно одна из сторон является владеющей (содержит
@JoinColumn), а другая — обратной (используетmappedBy).
2. Один-ко-многим (@OneToMany) / Многие-к-одному (@ManyToOne)
Это две стороны одной и той же связи. @ManyToOne всегда является владеющей стороной.
@Entity
public class Department {
@Id
private Long id;
@OneToMany(mappedBy = "department") // Обратная сторона
private List<Employee> employees = new ArrayList<>();
}
@Entity
public class Employee {
@Id
private Long id;
@ManyToOne(fetch = FetchType.LAZY) // Владеющая сторона, содержит внешний ключ
@JoinColumn(name = "department_id")
private Department department;
}
- Использование: Отдел и его сотрудники, заказ и позиции в заказе.
- Почему
@ManyToOne— владеющая: В таблицеEmployeeсоздаётся столбецdepartment_id. Это наиболее эффективное отображение.
3. Многие-ко-многим (@ManyToMany)
Каждая сущность может быть связана с коллекцией другой сущности. Реализуется через связующую таблицу (join table).
@Entity
public class Student {
@Id
private Long id;
@ManyToMany
@JoinTable(
name = "student_course", // Имя связующей таблицы
joinColumns = @JoinColumn(name = "student_id"),
inverseJoinColumns = @JoinColumn(name = "course_id")
)
private Set<Course> courses = new HashSet<>(); // Используйте Set для избежания дубликатов
}
@Entity
public class Course {
@Id
private Long id;
@ManyToMany(mappedBy = "courses") // Обратная сторона
private Set<Student> students = new HashSet<>();
}
- Использование: Студенты и курсы, теги и статьи.
- Важно: Одна из сторон должна быть владеющей (определяет
@JoinTable), другая — обратной (mappedBy).
Ключевые атрибуты для управления связями:
fetch(FetchType.LAZYилиFetchType.EAGER) — стратегия загрузки. Всегда предпочитайтеLAZYдля производительности. Данные загружаются только при обращении.cascade(CascadeType.ALL,PERSIST,MERGE, etc.) — определяет, какие операции с родительской сущностью распространяются на дочерние.orphanRemoval(true/false) — еслиtrue, при удалении сущности из коллекции (например,employees.remove(emp)) связанная сущность будет удалена из БД.
Рекомендация: Для связей @OneToMany и @ManyToMany всегда инициализируйте коллекции (new ArrayList<>(), new HashSet<>()), чтобы избежать NullPointerException.