Ответ
Связь «многие-ко-многим» (Many-to-Many) всегда реализуется через промежуточную таблицу (junction/join table), что фактически разбивает её на две связи «один-ко-многим» (One-to-Many).
Структура на примере Student и Course:
-- Основные таблицы
CREATE TABLE student (id SERIAL PRIMARY KEY, name TEXT);
CREATE TABLE course (id SERIAL PRIMARY KEY, title TEXT);
-- Промежуточная таблица (реализует Many-to-Many)
CREATE TABLE student_course (
student_id INT REFERENCES student(id) ON DELETE CASCADE,
course_id INT REFERENCES course(id) ON DELETE CASCADE,
enrolled_at TIMESTAMP DEFAULT NOW(), -- Дополнительные данные связи
PRIMARY KEY (student_id, course_id) -- Составной первичный ключ
);
Соответствующая модель в JPA/Hibernate:
@Entity
public class Student {
@Id @GeneratedValue
private Long id;
@ManyToMany
@JoinTable(
name = "student_course",
joinColumns = @JoinColumn(name = "student_id"),
inverseJoinColumns = @JoinColumn(name = "course_id")
)
private Set<Course> courses = new HashSet<>();
}
@Entity
public class Course {
@Id @GeneratedValue
private Long id;
@ManyToMany(mappedBy = "courses")
private Set<Student> students = new HashSet<>();
}
Ключевое преимущество промежуточной таблицы: Она позволяет хранить атрибуты связи (например, enrolled_at, grade), что невозможно при прямой связи Many-to-Many. Для работы с такими атрибутами промежуточную таблицу часто мапят на отдельную сущность (как в исходном ответе), что даёт полный контроль над связью.