Совместная таблица во многих-ко-многим не обновляется

#java #spring-boot #many-to-many

#java #весенняя загрузка #многие-ко-многим

Вопрос:

У меня есть отношение N: M между 2 сущностями, «Alumno» и «Curso».:

Alumno

 @Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "alumno")
public class Alumno {

    @Id
    @GeneratedValue
    private int id;
    private String name;
    private String dni;
    private int age;

    @ManyToMany(mappedBy = "alumnos", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    private List<Curso> cursos;


}
 

Curso

 @Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "curso")
public class Curso {
    @Id
    @GeneratedValue
    private int id;
    private String name;
    private int length;

    @ManyToMany
    private List<Alumno> alumnos;
}

 

Далее AlumnoService у меня есть следующие два метода:

     @Autowired
    private AlumnoRepository repository;

    @Autowired
    private CursoService cursoService;

...
//Non-related stuff
...

    public Alumno updateAlumno(Alumno alumno) {
        Alumno existingAlumno = repository.findById(alumno.getId()).orElse(null);
        existingAlumno.setName(alumno.getName());
        existingAlumno.setDni(alumno.getDni());
        existingAlumno.setAge(alumno.getAge());


        return repository.save(existingAlumno);
    }

    public Alumno insertCurso(int id_alumno, int id_curso) {
        Alumno alumno = repository.findById(id_alumno).orElse(null);
        System.out.println("Found alumno:  => "   alumno.getId()   " "   alumno.getName());
        Curso curso = cursoService.getCursoById(id_curso);
        System.out.println("Found curso:  => "   curso.getId()   " "   curso.getName());
        alumno.getCursos().add(curso);

        System.out.println("========");
        for (Curso c: alumno.getCursos()) {
            System.out.println(c.getId()   " "   c.getName());
        }
        System.out.println("==========");

        return updateAlumno(alumno);
    }
 

Согласно напечатанным строкам, все данные получены правильно, и на Postman я получаю правильный ответ:

 {
    "id": 2,
    "name": "Marta",
    "dni": "67242062K",
    "age": 15,
    "cursos": [
        {
            "id": 3,
            "name": "Bootstrap 4",
            "length": 11,
            "alumnos": []
        }
    ]
}
 

Это AlumnoController :

     @Autowired
    private AlumnoService service;

    @PutMapping("/insertCurso/{id_a}/{id_c}")
    public Alumno insertCurso(@PathVariable("id_a") int id_a, @PathVariable("id_c") int id_c) {
        return service.insertCurso(id_a, id_c);
    }
 

Однако после проверки базы данных общая таблица пуста:
Описание

Есть идеи, в чем может быть проблема? Я что-то забыл? Я совершенно новичок в весенних ботинках.

Спасибо вам за ваше время

С наилучшими пожеланиями

Комментарии:

1. Не могли бы вы, пожалуйста, опубликовать свой полный курс обслуживания выпускников?

Ответ №1:

Попробуйте использовать @Transactional аннотацию из org.springframework.transaction.annotation пакета и посмотрите, работает ли это.

Вот так:

 @Transactional
public Alumno insertCurso(int id_alumno, int id_curso) {
    Alumno alumno = repository.findById(id_alumno).orElse(null);
    System.out.println("Found alumno:  => "   alumno.getId()   " "   alumno.getName());
    Curso curso = cursoService.getCursoById(id_curso);
    System.out.println("Found curso:  => "   curso.getId()   " "   curso.getName());
    alumno.getCursos().add(curso);

    System.out.println("========");
    for (Curso c: alumno.getCursos()) {
        System.out.println(c.getId()   " "   c.getName());
    }
    System.out.println("==========");

    return updateAlumno(alumno);
}
 

Ответ №2:

Я обнаружил, что проблема заключалась в аннотациях объектов. Вот решение, которое (насколько я знаю) работает:

Alumno

 @Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "alumno")
public class Alumno {

    @Id
    @GeneratedValue
    private int id;
    private String name;
    private String dni;
    private int age;

    @ManyToMany(cascade = CascadeType.ALL)
    @JoinTable(name = "matriculas",
            joinColumns = @JoinColumn(name = "alumno_id"),
            inverseJoinColumns = @JoinColumn(name = "curso_id")
    )
    @JsonIgnore
    private List<Curso> cursos = new ArrayList<>();


}
 

Здесь я добавил @JsonIgnore, чтобы избежать рекурсии, приводящей к переполнению стека при отображении списков.

Curso

 @Data
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "curso")
public class Curso {
    @Id
    @GeneratedValue
    private int id;
    private String name;
    private int length;

    @ManyToMany(cascade = CascadeType.ALL, mappedBy = "cursos")
    private List<Alumno> alumnos = new ArrayList<>();
}

 

Здесь я добавил mappedBy атрибут в @ManyToMany. Это было причиной, по которой она не реплицировалась правильно.