I have a relation N:M between 2 entities, “Alumno” and “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; }
On AlumnoService
I have the following two methods:
@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); }
According to the printed lines, all the data is fetch correctly, and on Postman I get a correct answer:
{ "id": 2, "name": "Marta", "dni": "67242062K", "age": 15, "cursos": [ { "id": 3, "name": "Bootstrap 4", "length": 11, "alumnos": [] } ] }
This is the 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); }
However, upon inspecting the database, the shared table is empty:
Any idea on what the issue might be? Did I forget something? I’m completely new to Spring boot.
Thank you for your time
Best regards
Advertisement
Answer
I found the problem was on the annotations of the entities. Here is a solution that (as far as I know) works:
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<>(); }
Here I added the @JsonIgnore to avoid recursion leading to a stack overflow while displaying the lists.
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<>(); }
Here I added the mappedBy
attribute to the @ManyToMany. This was the reason it wasn’t replicating correctly.