cot_shaurma
@cot_shaurma
Java и всего понемногу

По какому принципу Spring DataJPA обновляет записи в связанных таблицах?

Имеется две сущности со связью ManyToMany: Student и Course. У студента может быть несколько курсов, а один курс может проходить несколько студентов. Эту связь я отображаю в такой таблице:

CREATE TABLE student_courses
(
    student_id INTEGER NOT NULL,
    course_id INTEGER NOT NULL,
    CONSTRAINT student_course_idx UNIQUE (student_id, course_id),
    FOREIGN KEY (student_id) REFERENCES students (id) ON DELETE CASCADE,
    FOREIGN KEY (course_id) REFERENCES courses (id) ON DELETE CASCADE
);


Сущность Student:

@Entity
@Table(name = "students")
public class Student {
    @ManyToMany(fetch = FetchType.LAZY)
    @JoinTable(
            name = "students_courses",
            joinColumns = @JoinColumn(name = "student_id"),
            inverseJoinColumns = @JoinColumn(name = "course_id")
    )
    List<Course> courses;
    // другие поля
}


Сущность Course:

@Entity
@Table(name = "courses")
public class Course {
    @ManyToMany(mappedBy = "courses", fetch = FetchType.LAZY)
    List<Student> students;
    // другие поля
}


Я работаю с базой данных через Spring DataJpa. То есть использую JpaRepository, который принимает сущности и автоматически обновляет/удаляет/сохраняет. Например, вот репозиторий для курса (для студента такой же, только называется CrudStudentRepository):

@Transactional(readOnly = true)
public interface CrudCourseRepository extends JpaRepository<Course, Integer> {
}


Вопрос.

Как JpaRepository производит обновление связей в таблице student_courses? У сущности Student есть поле List<Course> courses. Насколько я понимаю, если я попытаюсь обновить сущность Student, передав в CrudStudentRepository#save() студента с пустым списком курсов, то в таблице student_courses будут удалены все записи, в которых фигурирует обновляемый студент, но в реальности этого не происходит. По какому принципу JpaRepository удаляет или обновляет связи в таблице связей, student_courses в данном случае? Почему я обновляю запись о студенте, передавая в репозиторий сущность Student с пустым списком курсов, но записи о связях этого студента с курсами не удаляются из student_courses?
  • Вопрос задан
  • 748 просмотров
Пригласить эксперта
Ответы на вопрос 1
azerphoenix
@azerphoenix Куратор тега Java
Java Software Engineer
Приветствую, коллега!
Позволь, внести небольшую лепту в ваш код и отметить следующее:
CrudCourseRepository

Наверное, указывать Crud в названии не нужно, так как в репозиторий в будущем могут быть добавлены другие методы и соответственно, с точки зрения clean code название не будет корректным.

Как JpaRepository производит обновление связей в таблице student_courses?

Как говорится, лучше один раз увидеть, чем сто раз услышать. Так что лучше включить в properties
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true


Предположу, что вы увидите примерно следующее:
Запрос на SELECT (выборку) из двух таблиц вместе с JOIN, а далее запрос на вставку новой записи (INSERT)

Насколько я понимаю, если я попытаюсь обновить сущность Student, передав в CrudStudentRepository#save() студента с пустым списком курсов, то в таблице student_courses будут удалены все записи, в которых фигурирует обновляемый студент, но по моему опыту этого не происходит. Как мне тогда удалять/обновлять эти записи?

Тут пожалуй, вам стоит обратить внимание на CascadeType.

Например, если в связи OneToMany вы постараетесь сохранить список со стороны самой сущности, то элементы списка будут сохранены, но id у них будет null, так как сама сущность еще не сохранена и ей не присвоен идентификатор. Чтобы избежать этого можно как вариант, указать CascadeType.All или PERSIST & MERGE

В случае с ManyToMany, думаю, что будет корректным указать тип каскада. Например, CascadeType.PERSIST CascadeType.MERGE

К слову, есть хороший источник, откуда я также время от времени черпаю информацию. Вот ссылка - link
Можешь глянуть.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы