Many to many map java

Spring Data JPA Many To Many Relationship Mapping Example

In previous articles, I wrote about how to use one-to-one and one-to-many relationship mappings in Spring Data JPA.

In this article, you’ll learn how to map a many-to-many bidirectional relationship using Spring Data JPA and MySQL in a Spring Boot application.

Many-to-many relationships are one of the most commonly used association mappings and require an additional database table to hold the primary keys of both relationship tables.

Let us create a new project from scratch and learn how to implement a many-to-many relationship mapping using Spring Data JPA and MySQL.

To use Spring Data JPA with the MySQL database in Spring Boot, you need both spring-data-starter-data-jpa and mysql-connector-java dependencies. Add the following dependencies to your Gradle project’s build.gradle file:

implementation 'org.springframework.boot:spring-boot-starter-data-jpa' runtimeOnly 'mysql:mysql-connector-java' 
dependency> groupId>org.springframework.bootgroupId> artifactId>spring-boot-starter-data-jpaartifactId> dependency> dependency> groupId>mysqlgroupId> artifactId>mysql-connector-javaartifactId> scope>runtimescope> dependency> 

If you are starting a new project, just use Spring Initializr web tool to bootstrap a new Spring Boot application with the above dependencies.

Spring Boot automatically configures DataSource for in-memory databases like H2 database, HSQLDB, and Apache Derby. For a MySQL database, you need to explicitly define the database connection properties in a properties file. Open the application.properties file and copy and paste the following properties:

# MySQL connection properties spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.username=root spring.datasource.password=mypass spring.datasource.url=jdbc:mysql://localhost:3306/testdb?createDatabaseIfNotExist=true&useSSL=false # Log JPA queries # Comment this in production spring.jpa.show-sql=true # Drop and create new tables (create, create-drop, validate, update) # Only for testing purposes - comment this in production spring.jpa.hibernate.ddl-auto=create # Hibernate SQL dialect spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect 

Spring Boot will automatically configure a DataSource bean based on the above properties. Just make sure to change the spring.datasource.username and spring.datasource.password properties to match your MySQL database installation. The hibernate property spring.jpa.hibernate.ddl-auto = create will automatically create database tables based on the entity classes when the application starts. The createDatabaseIfNotExist=true configuration property, included in spring.datasource.url , automatically creates the database schema if it doesn’t already exist.

Spring Data JPA Many To Many Mapping

A many-to-many relationship refers to the relationship between two entities/tables A and B in which one element/row of A may only be associated with many elements/rows of B and vice versa. A typical example of such a many-to-many relationship is the relationship between students and courses. A student can enroll in multiple courses, and a course can have more than one student, thus forming a many-to-many relationship. To model the above relationship in the database, you need to create three tables, one each for both students and courses and another one for holding relationship keys, as shown below in the Entity-Relationship (ER) diagram: students_courses is a join table that contains two foreign keys, student_id and course_id , to reference both students and courses database tables. Both these foreign keys also act as a composite primary key for the students_courses table.

We need to create two entity classes, Student and Course , to map the above many-to-many relationship. You don’t need to create a separate entity class for the join table. Here is what our entity classes look like: Student.java

package com.attacomsian.jpa.many2many.domains; import javax.persistence.*; import java.io.Serializable; import java.util.Set; @Entity @Table(name = "students") public class Student implements Serializable  @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private int age; private String grade; @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST) @JoinTable(name = "students_courses", joinColumns =  @JoinColumn(name = "student_id", referencedColumnName = "id", nullable = false, updatable = false)>, inverseJoinColumns =  @JoinColumn(name = "course_id", referencedColumnName = "id", nullable = false, updatable = false)>) private SetCourse> courses = new HashSet>(); public Student()  > public Student(String name, int age, String grade)  this.name = name; this.age = age; this.grade = grade; > // getters and setters, equals(), toString() . (omitted for brevity) > 
package com.attacomsian.jpa.many2many.domains; import javax.persistence.*; import java.io.Serializable; import java.util.Set; @Entity @Table(name = "courses") public class Course implements Serializable  @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String title; private String abbreviation; private int modules; private double fee; @ManyToMany(mappedBy = "courses", fetch = FetchType.LAZY) private SetStudent> students = new HashSet>(); public Course()  > public Course(String title, String abbreviation, int modules, double fee)  this.title = title; this.abbreviation = abbreviation; this.modules = modules; this.fee = fee; > // getters and setters, equals(), toString() . (omitted for brevity) > 

Both Student and Course classes are annotated with the Entity annotation to indicate that they are JPA entities. The @Table annotation is used to specify the name of the database table that should be mapped to this entity. The id attributes are annotated with both @Id and @GeneratedValue annotations. The former indicates that they are the primary keys of the entities. The latter defines the primary key generation strategy. In the above case, we have declared that the primary key should be an AUTO INCREMENT field.

A many-to-many relationship between two entities is defined using the @ManyToMany annotation in Spring Data JPA. It uses the mappedBy attribute to indicate the entity that owns the bidirectional relationship. In a bidirectional relationship, the @ManyToMany annotation is defined in both entities, but only one entity can own the relationship. We picked the Student class as an owner of the relationship in the above example.

The @JoinTable annotation defines the join table between two entities on the owner’s side of the relationship. We have used this annotation to define the students_courses table. If the @JoinTable is left out, the default values of the annotation elements apply. The name of the join table is supposed to be the table names of the associated primary tables concatenated together (owning side first) using an underscore.

The next step is to define the repository interfaces for storing and accessing the data from the database. We shall extend our repositories from Spring Data JPA’s CrudRepository interface that provides methods for generic CRUD operations. StudentRepository.java

package com.attacomsian.jpa.many2many.repositories; import com.attacomsian.jpa.many2many.domains.Student; import org.springframework.data.repository.CrudRepository; import java.util.List; public interface StudentRepository extends CrudRepositoryStudent, Long>  ListStudent> findByNameContaining(String name); > 
package com.attacomsian.jpa.many2many.repositories; import com.attacomsian.jpa.many2many.domains.Course; import org.springframework.data.repository.CrudRepository; import java.util.List; public interface CourseRepository extends CrudRepositoryCourse, Long>  ListCourse> findByTitleContaining(String title); ListCourse> findByFeeLessThan(double fee); > 

We also defined a few derived query methods like findByFeeLessThan() to retrieve all courses that have a fee less than the given value and more. That is it. You are done with defining a many-to-many relationship mapping in Spring Data JPA.

Now is the time to create the main application class for our Spring Boot console application to test our many-to-many relationship mapping: Application.java

package com.attacomsian.jpa; import com.attacomsian.jpa.many2many.domains.Course; import com.attacomsian.jpa.many2many.domains.Student; import com.attacomsian.jpa.many2many.repositories.CourseRepository; import com.attacomsian.jpa.many2many.repositories.StudentRepository; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import java.util.Arrays; @SpringBootApplication public class Application  public static void main(String[] args)  SpringApplication.run(Application.class, args); > @Bean public CommandLineRunner mappingDemo(StudentRepository studentRepository, CourseRepository courseRepository)  return args ->  // create a student Student student = new Student("John Doe", 15, "8th"); // save the student studentRepository.save(student); // create three courses Course course1 = new Course("Machine Learning", "ML", 12, 1500); Course course2 = new Course("Database Systems", "DS", 8, 800); Course course3 = new Course("Web Basics", "WB", 10, 0); // save courses courseRepository.saveAll(Arrays.asList(course1, course2, course3)); // add courses to the student student.getCourses().addAll(Arrays.asList(course1, course2, course3)); // update the student studentRepository.save(student); >; > > 

Next, run the application to see the output. If you are using Gradle, execute the following command to start the application:

Hibernate: drop table if exists courses Hibernate: drop table if exists students Hibernate: drop table if exists students_courses Hibernate: create table courses (id bigint not null auto_increment, abbreviation varchar(255), fee double precision not null, modules integer not null, title varchar(255), primary key (id)) engine=InnoDB Hibernate: create table students (id bigint not null auto_increment, age integer not null, grade varchar(255), name varchar(255), primary key (id)) engine=InnoDB Hibernate: create table students_courses (student_id bigint not null, course_id bigint not null, primary key (student_id, course_id)) engine=InnoDB Hibernate: insert into students (age, grade, name) values (?, ?, ?) Hibernate: insert into courses (abbreviation, fee, modules, title) values (?, ?, ?, ?) Hibernate: insert into courses (abbreviation, fee, modules, title) values (?, ?, ?, ?) Hibernate: insert into courses (abbreviation, fee, modules, title) values (?, ?, ?, ?) Hibernate: select student0_.id as id1_4_0_, student0_.age as age2_4_0_, student0_.grade as grade3_4_0_, student0_.name as name4_4_0_ from students student0_ where student0_.id=? Hibernate: select courses0_.student_id as student_1_5_0_, courses0_.course_id as course_i2_5_0_, course1_.id as id1_2_1_, course1_.abbreviation as abbrevia2_2_1_, course1_.fee as fee3_2_1_, course1_.modules as modules4_2_1_, course1_.title as title5_2_1_ from students_courses courses0_ inner join courses course1_ on courses0_.course_id=course1_.id where courses0_.student_id=? Hibernate: select course0_.id as id1_2_0_, course0_.abbreviation as abbrevia2_2_0_, course0_.fee as fee3_2_0_, course0_.modules as modules4_2_0_, course0_.title as title5_2_0_ from courses course0_ where course0_.id=? Hibernate: select course0_.id as id1_2_0_, course0_.abbreviation as abbrevia2_2_0_, course0_.fee as fee3_2_0_, course0_.modules as modules4_2_0_, course0_.title as title5_2_0_ from courses course0_ where course0_.id=? Hibernate: select course0_.id as id1_2_0_, course0_.abbreviation as abbrevia2_2_0_, course0_.fee as fee3_2_0_, course0_.modules as modules4_2_0_, course0_.title as title5_2_0_ from courses course0_ where course0_.id=? Hibernate: insert into students_courses (student_id, course_id) values (?, ?) Hibernate: insert into students_courses (student_id, course_id) values (?, ?) Hibernate: insert into students_courses (student_id, course_id) values (?, ?) ... 

That’s all for this article. You learned how to map and use a many-to-many relationship using Spring Data JPA and MySQL in a Spring Boot application. Don’t forget to subscribe for updates if you want to be the first to know when new tutorials are available.

  • Getting Started with Spring Data JPA
  • Spring Data JPA with H2 DataBase and Spring Boot
  • Accessing Data with Spring Data JPA and MySQL
  • Derived Query Methods in Spring Data JPA
  • Spring Data JPA Custom Queries using @Query Annotation
  • How to Use Spring Data JPA Named Queries
  • Sorting Query Results in Spring Data JPA
  • Pagination with Spring Data JPA
  • Spring Data JPA One To One Relationship Mapping Example
  • Spring Data JPA One To Many Relationship Mapping Example
  • Spring Data JPA Composite Primary Key Mapping Example

✌️ Like this article? Follow me on Twitter and LinkedIn. You can also subscribe to RSS Feed.

Источник

Читайте также:  Debian php in console
Оцените статью