Advertisement

Google Ad Slot: content-top

Spring Boot Many-to-One Mapping

~1 min read · Spring Boot
On this page

Many-to-Many relationships occur when multiple entities relate to multiple entities. Example:

  • Students can enroll in multiple Courses
  • Courses can have multiple Students


Define Student and Course Entities

We'll create a bidirectional Many-to-Many relationship between Student and Course


Student.java
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import jakarta.persistence.*; import java.util.HashSet; import java.util.Set; @Entity public class Student { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}) @JoinTable( name = "student_course", joinColumns = @JoinColumn(name = "student_id"), inverseJoinColumns = @JoinColumn(name = "course_id") ) @JsonIgnoreProperties("students") // ✅ Prevents infinite loop private Set courses = new HashSet<>(); // Getters and Setters public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set getCourses() { return courses; } public void setCourses(Set courses) { this.courses = courses; } }

This creates a join tablestudent_course to link students and courses.

Course.java
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import jakarta.persistence.*; import java.util.HashSet; import java.util.Set; @Entity public class Course { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String title; @ManyToMany(mappedBy = "courses") // No @JoinTable here (already in Student) @JsonIgnoreProperties("courses") // ✅ Prevents infinite loop private Set students = new HashSet<>(); // Getters and Setters public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public Set getStudents() { return students; } public void setStudents(Set students) { this.students = students; } }

Bidirectional Mapping: The relationship is mapped from Student to Course.

Table name : student

id name

Table name : course

id name

Table name : student_course

student_id course_id

Create JPA Repositories

StudentRepository.java
import org.springframework.data.jpa.repository.JpaRepository; public interface StudentRepository extends JpaRepository { }
CourseRepository.java
import org.springframework.data.jpa.repository.JpaRepository; public interface CourseRepository extends JpaRepository { }

Create Services

StudentService.java
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @Service public class StudentService { @Autowired private StudentRepository studentRepository; @Autowired private CourseRepository courseRepository; // ✅ Create Student & Courses public Student createStudentWithCourse(Student student) { Set savedCourses = student.getCourses().stream() .map(course -> courseRepository.save(course)) .collect(Collectors.toSet()); student.setCourses(savedCourses); return studentRepository.save(student); } // ✅ Create Student & Assign Courses public Student createStudent(StudentDTO studentDTO) { Student student = new Student(); student.setName(studentDTO.getName()); Set courses = studentDTO.getCourseIds().stream() .map(courseRepository::findById) .filter(Optional::isPresent) .map(Optional::get) .collect(Collectors.toSet()); student.setCourses(courses); return studentRepository.save(student); } // ✅ Create Student Only public Student createStudentOnly(Student student) { return studentRepository.save(student); } // ✅ Get Student by ID public Student getStudent(Long id) { return studentRepository.findById(id).orElseThrow(() -> new RuntimeException("Student Not Found")); } // ✅ Add Courses to an Existing Student public Student addCoursesToStudent(Long studentId, Set courseIds) { Student student = studentRepository.findById(studentId).orElseThrow(() -> new RuntimeException("Student Not Found")); Set courses = courseIds.stream() .map(courseRepository::findById) .filter(Optional::isPresent) .map(Optional::get) .collect(Collectors.toSet()); student.getCourses().addAll(courses); return studentRepository.save(student); } // ✅ Delete Student public String deleteStudent(Long studentId) { studentRepository.deleteById(studentId); return "Deleted Successfully"; } }

Create Controllers

StudentController.java
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.Set; @RestController @RequestMapping("/students") public class StudentController { @Autowired private StudentService studentService; // ✅ Create Student with Courses @PostMapping public ResponseEntity createStudentWithCourse(@RequestBody Student student) { return ResponseEntity.ok(studentService.createStudentWithCourse(student)); } // ✅ Create Student with Courses @PostMapping("/createStudent") public ResponseEntity createStudent(@RequestBody StudentDTO studentDTO) { return ResponseEntity.ok(studentService.createStudent(studentDTO)); } // ✅ Create Student with Courses @PostMapping("/createStudentOnly") public ResponseEntity createStudentOnly(@RequestBody Student student) { return ResponseEntity.ok(studentService.createStudentOnly(student)); } // ✅ Get Student with Courses @GetMapping("/{id}") public ResponseEntity getStudent(@PathVariable Long id) { return ResponseEntity.ok(studentService.getStudent(id)); } // ✅ Add Courses to Existing Student @PutMapping("/{id}/courses") public ResponseEntity addCourses(@PathVariable Long id, @RequestBody Set courseIds) { return ResponseEntity.ok(studentService.addCoursesToStudent(id, courseIds)); } // ✅ Add Courses to Existing Student @DeleteMapping("/{id}") public ResponseEntity deleteCourses(@PathVariable Long id) { return ResponseEntity.ok(studentService.deleteStudent(id)); } }

Testing the REST API with Postman:

Once the application is running, test the endpoints:


Create Students with Courses POST:http://localhost:8080/students

Create a Student with Existing Courses POST:http://localhost:8080/students/createStudent

Get Student with Courses GET:http://localhost:8080/students/{studentID}

Create Student Only POST:http://localhost:8080/students/createStudentOnly

Add More Courses to Student PUT:http://localhost:8080/students/{studentID}/courses

Delete Courses with Student DELETE:http://localhost:8080/students/{studentID}