0

I have 3 tables

  1. Student
  2. Course
  3. Enrolled Course (Join Table)

There is a many-to-many relationship between student and course. Since a student can enroll in many courses and a course can have many students enrolled.

I added the corresponding List(students) and Set(courses) in Course and Student entity classes respectively.

The Student Entity:

    @Entity
    @Table(name="Student_Tbl")
    public class Student {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "id")
        private Long id;
    
        private String name;
    
        private String department;
    
        @JoinTable(
                name = "enrolled_course",
                joinColumns = @JoinColumn(name = "student_id",referencedColumnName = "id"),
                inverseJoinColumns = @JoinColumn(name = "course_id",referencedColumnName = "title"))
        @ManyToMany(fetch = FetchType.EAGER,cascade = CascadeType.ALL)
        private Set<Course> courses;

The Course Entity:

    @Entity
    @Table(name="Course_Tbl")
    public class Course {
        @Id
        private String title;
    
        private String description;
    
        @ManyToMany(mappedBy = "courses",fetch = FetchType.EAGER)
        private Set<Student> students;

The Controller Class:

    @RestController
    @RequestMapping("/v1")
    public class StudentController {
      
        @Autowired
        private StudentRepository studentRepository;

        @Autowired
        private CourseRepository courseRepository;
    
        @Autowired
        private StudentService studentService;
    
        @PostMapping("/student/register")
        public ResponseEntity<Student> saveStudent(@RequestBody Student student)
        {
            studentService.saveStudent(student);
            return ResponseEntity.ok(student);
        }
    }

When I save a Student with a course, it all works well. The data is stored in all the three tables

    {
        "name":"ABC",
        "department":"CS",
        "course":[
            {
                "title":"DBMS",
                "description":"Database Management System"
            }
            
        ]
    }

But when I post another request with the same course for different students, Duplicate entry 'DBMS' for key 'course_tbl.PRIMARY' error is thrown.

How do I avoid this?

Edit:

public void saveStudent(Student student){
        for(Course course : student.getCourse() ){
            if(courseRepository.findByTitle(course.getTitle())!= null) continue;
            courseRepository.save(course);
        }
        studentRepository.save(student);
    }

Here I manually handled the case by checking if the course is already present in the table which worked as expected.

  • The problem comes from the `CascateType.ALL` on the `@ManyToMany courses`. When you create a student, hibernate tries to create the course. see https://stackoverflow.com/questions/4935095/jpa-hibernate-many-to-many-cascading. You will see that there is no 100% satisfying solution. – Pierre Demeestere Nov 13 '22 at 07:59
  • Yeah, I saw this and tried. I'm new to Spring boot and trying to find a solution to tackle this situation. All the materials I found on web doesn't speak about this use case. Any suggestions on how to get this working? – ManishBharathi Nov 13 '22 at 08:24
  • It seems that if none of the entity (course and student) is the owner of the relation, there is no way to get it to work properly with a cascade strategy. – Pierre Demeestere Nov 13 '22 at 09:09
  • Using `CascadeType.MERGE` & `CascadeType.REFRESH` I was able to prevent the duplicate from creating. Thanks @PierreDemeestere – ManishBharathi Nov 13 '22 at 11:53
  • Yes, but would it create the `course` if it did not exist : probably not. And would it work as well from the other side : i.e. creating a course containing a student ? – Pierre Demeestere Nov 13 '22 at 12:52
  • Could you show the source code of `studentService.saveStudent(student)` ? – Pierre Demeestere Nov 13 '22 at 12:58
  • Moreover, I think that, despite the MERGE, when you create a student with an existing course, if you try to change the name of the course via the inner Json structure discribing the course, then you will see no change in the database unless you use PERSIST instead of MERGE. But you will have another problem. Suppose that the existing course has already some students, you have to check if these relations won't be lost. You really have to check all data possibilities. – Pierre Demeestere Nov 13 '22 at 13:19
  • Can a student create a course or is the course already available for students to join? – FredvN Nov 13 '22 at 13:41
  • @FredvN The use case is the course should be available, if not should be added. – ManishBharathi Nov 14 '22 at 11:03

0 Answers0