Open In App

JPA – Many-To-Many Mapping

Last Updated : 09 Apr, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

JPA Many-To-Many Mapping provides the many-to-many relationship representing the association between the two entities where each instance of the one entity can be associated with the multiple instances of the other entity.

Many-to-many mapping is used when multiple instances of one entity are associated with multiple instances of another entity, and it forms the many-to-many relationship. In database terms, it can be typically implemented using the join table that links the primary keys of both entities.

Steps to Implement Many-To-Many Mapping in JPA

1. Define the entities involved in the relationship.

We can identify the entities that participate in many-to-many relationships. For example, we can consider the entities of the Student and Course.

Student Entity:

@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String name;

@ManyToMany(mappedBy = "students")
private Set<Course> courses = new HashSet<>();

// Getters and setters
}

Course Entity:

@Entity
public class Course {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String name;

@ManyToMany
@JoinTable(
name = "course_student",
joinColumns = @JoinColumn(name = "course_id"),
inverseJoinColumns = @JoinColumn(name = "student_id")
)
private Set<Student> students = new HashSet<>();

// Getters and setters
}

2. Configure the Relationships of the Entities

We can use the annotations such as @ManyToMany and it defines the relationship between the entities. In Course entity, we can use the @JoinTable to specify the join table names and the columns.

3. Map to the Join Table

In the course entity, we can use @JoinTable annotation to the map the join table that can links the Course and Student entities of the application.

 @ManyToMany
@JoinTable(
name = "course_student", // Name of the join table
joinColumns = @JoinColumn(name = "course_id"), // Column in the join table that references Course
inverseJoinColumns = @JoinColumn(name = "student_id") // Column in the join table that references Student
)
private Set<Student> students = new HashSet<>();

4. Access and Manipulate the Associated Entities

Once the entites are properly can be configured and persisted. We can access and manipulate the associated entities as needed to the application.

// Creating a new student
Student student = new Student();
student.setName("John");

// Creating a new course
Course course = new Course();
course.setName("Math");

// Associating the student with the course
student.getCourses().add(course);
course.getStudents().add(student);

// Saving the entities
entityManager.getTransaction().begin();
entityManager.persist(student);
entityManager.persist(course);
entityManager.getTransaction().commit();

// Retrieving a student and accessing associated courses
Student retrievedStudent = entityManager.find(Student.class, student.getId());
Set<Course> courses = retrievedStudent.getCourses();
for (Course c : courses) {
System.out.println("Course Name: " + c.getName());
}

// Retrieving a course and accessing associated students
Course retrievedCourse = entityManager.find(Course.class, course.getId());
Set<Student> students = retrievedCourse.getStudents();
for (Student s : students) {
System.out.println("Student Name: " + s.getName());
}

Project Implementation of JPA Many-To-Many Mapping

Below are the steps to implement many-to-many mapping in JPA.

Step 1: Create the new JPA project using the InteljIdea named as jpa-many-to-many-mapping-demo.

Step 2: Open open.xml and add the below dependencies into the XML file.

Dependencies:

  <dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-core</artifactId>
<version>6.0.2.Final</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>

Project Structure:

After creating the Project, the folder structure will look like below:

Project Structure


Step 3: Open persistence.xml and put the below code into the project to configure the database.

XML
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<persistence xmlns="https://jakarta.ee/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd"
             version="3.0">
    <persistence-unit name="jpa-example">
        <class>model.Course</class>
        <class>model.Student</class>
        <class>service.CourseService</class>
        <class>service.StudentService</class>
        <properties>
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/example"/>
            <property name="javax.persistence.jdbc.user" value="root"/>
            <property name="javax.persistence.jdbc.password" value=""/>
            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
            <property name="hibernate.hbm2ddl.auto" value="update"/>
        </properties>

    </persistence-unit>
</persistence>


Step 4: Create a Java package named model and in that package create a Entity class named Student.

Go to src > main > java > model > Student and put the below code.

Java
package model;

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(mappedBy = "students")
    private Set<Course> courses = new HashSet<>();

    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<Course> getCourses() {
        return courses;
    }

    public void setCourses(Set<Course> courses) {
        this.courses = courses;
    }
}


Step 5: Create a new Entity class named Course.

Go to src > main > java > model > Course and put the below code.

Java
package model;

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 name;

    @ManyToMany
    @JoinTable(
            name = "course_student",
            joinColumns = @JoinColumn(name = "course_id"),
            inverseJoinColumns = @JoinColumn(name = "student_id")
    )
    private Set<Student> students = 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<Student> getStudents() {
        return students;
    }

    public void setStudents(Set<Student> students) {
        this.students = students;
    }
}


Step 6: Create a new Java package named as service. In that package, create a new Entity Java class named StudentService.

Go to src > main > java > service > StudentService and put the below code.

Java
package service;

import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.EntityTransaction;
import jakarta.persistence.PersistenceContext;
import jakarta.transaction.Transactional;
import model.Student;

import java.util.List;

public class StudentService {
    private EntityManager entityManager;

    public StudentService(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    public List<Student> getAllStudents() {
        return entityManager.createQuery("SELECT s FROM Student s", Student.class).getResultList();
    }

    @Transactional
    public Student saveStudent(Student student) {
        EntityTransaction transaction = entityManager.getTransaction();
        transaction.begin();
        entityManager.persist(student);
        transaction.commit();
        return student;
    }

    public Student getStudentById(Long id) {
        return entityManager.find(Student.class, id);
    }  
}


Step 7: Create a new Entity Java class named CourseService .

Go to src > main > java > service > CourseService and put the below code.

Java
package service;

import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.EntityTransaction;
import jakarta.persistence.PersistenceContext;
import jakarta.transaction.Transactional;
import model.Course;

import java.util.List;
@Transactional
public class CourseService {
    private EntityManager entityManager;

    public CourseService(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    public List<Course> getAllCourses() {
        return entityManager.createQuery("SELECT c FROM Course c", Course.class).getResultList();
    }


    public Course saveCourse(Course course) {
        EntityTransaction transaction = entityManager.getTransaction();
        transaction.begin();
        entityManager.persist(course);
        transaction.commit();
        return course;
    }

    public Course getCourseById(Long id) {
        return entityManager.find(Course.class, id);
    }  
}


Step 8: Create a new Java class named as the MainApplication.

Go to src > main > java > MainApplication and write the below code..

Java
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;
import model.Course;
import model.Student;
import service.CourseService;
import service.StudentService;

import java.util.List;

public class MainApplication {
    public static void main(String[] args) {
        // Create EntityManagerFactory using persistence unit name defined in persistence.xml
        EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("jpa-example");

        // Instantiate services
        CourseService courseService = new CourseService(entityManagerFactory.createEntityManager());
        StudentService studentService = new StudentService(entityManagerFactory.createEntityManager());

        // Add some courses
        Course mathCourse = new Course();
        mathCourse.setName("Java");
        courseService.saveCourse(mathCourse);

        Course scienceCourse = new Course();
        scienceCourse.setName("Python");
        courseService.saveCourse(scienceCourse);

        // Add some students
        Student johnStudent = new Student();
        johnStudent.setName("Mahesh Kadambala");
        johnStudent.getCourses().add(mathCourse);
        johnStudent.getCourses().add(scienceCourse);
        studentService.saveStudent(johnStudent);

        Student aliceStudent = new Student();
        aliceStudent.setName("Eswar Beta");
        aliceStudent.getCourses().add(mathCourse);
        studentService.saveStudent(aliceStudent);

        // Retrieve and print courses
        List<Course> courses = courseService.getAllCourses();
        System.out.println("Courses:");
        for (Course course : courses) {
            System.out.println(course.getId() + ": " + course.getName());
        }

        // Retrieve and print students
        List<Student> students = studentService.getAllStudents();
        System.out.println("\nStudents:");
        for (Student student : students) {
            System.out.println(student.getId() + ": " + student.getName());
            System.out.println("Courses:");
            for (Course course : student.getCourses()) {
                System.out.println(" - " + course.getName());
            }
        }

        // Close the EntityManagerFactory when done
        entityManagerFactory.close();
    }
}
  • The MainApplication class initializes an EntityManagerFactory based on the persistence unit defined in persistence.xml.
  • Then it instantiates CourseService and StudentService to manage course and student entities respectively.
  • Courses and students are added to the database, and then retrieved and printed.
  • Finally, the EntityManagerFactory is closed to release resources.

pom.xml:

XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>jpa-many-to-many-mapping-demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <name>jpa-many-to-many-mapping-demo</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.target>11</maven.compiler.target>
        <maven.compiler.source>11</maven.compiler.source>
        <junit.version>5.9.2</junit.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.hibernate.orm</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>6.0.2.Final</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jaxb</groupId>
            <artifactId>jaxb-runtime</artifactId>
            <version>3.0.2</version>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.28</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
        </plugins>
    </build>
</project>


Step 9: Once the project is completed, run the application. After running, it will show the courses and Students with courses as output. Refer the below image for the better understanding of the concept.

Output Screen

By the following these steps and the understanding the annotations involved, developers can be effectively implement and manage the many-to-many relationships in the JPA application.



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads