Check out my Udemy course to Learn Spring Data JPA : Master Spring Data JPA with Hibernate
Many to Many Bidirectional Mapping - ER Diagram
1. Creating Spring Boot Project
Spring Boot provides a web tool called https://start.spring.io to bootstrap an application quickly. Just go to https://start.spring.io and generate a new spring boot project.Use the below details in the Spring boot creation:
Project Name: spring-data-jpa-course
Project Type: Maven
Choose dependencies: Spring Data JPA, MySQL Driver, Lombok
Package name: net.javaguides.springboot
Use the below details in the Spring boot creation:
Project Name: spring-data-jpa-course
Project Type: Maven
Choose dependencies: Spring Data JPA, MySQL Driver, Lombok
Package name: net.javaguides.springboot
2. Maven Dependencies
Here is the complete pom.xml for your reference:
<?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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>net.javaguides</groupId>
<artifactId>spring-data-jpa-course</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-data-jpa-course</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3. Configure MySQL database
Let's use the MySQL database to store and retrieve the data in this example and we gonna use Hibernate properties to create and drop tables.
Open the application.properties file and add the following configuration to it:spring.datasource.url=jdbc:mysql://localhost:3306/demo?useSSL=false
spring.datasource.username=root
spring.datasource.password=Mysql@123
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQLDialect
spring.jpa.hibernate.ddl-auto = create-drop
Make sure that you will create a demo database before running the Spring boot application.Also, change the MySQL username and password as per your MySQL installation on your machine.
spring.datasource.url=jdbc:mysql://localhost:3306/demo?useSSL=false
spring.datasource.username=root
spring.datasource.password=Mysql@123
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQLDialect
spring.jpa.hibernate.ddl-auto = create-drop
4. Create JPA Entities
Let's create an entity package inside a base package "net.javaguides.springboot".
User.java
package com.springdatajpa.springboot.entity;
import lombok.Getter;
import lombok.Setter;
import jakarta.persistence.*;
import java.util.HashSet;
import java.util.Set;
@Getter
@Setter
@Entity
@Table(
name = "users",
uniqueConstraints = @UniqueConstraint(
name = "unique_email",
columnNames = "email"
)
)
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String firstName;
private String lastName;
private String email;
private String password;
@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinTable(
name = "users_roles",
joinColumns = @JoinColumn(
name = "user_id", referencedColumnName = "id"
),
inverseJoinColumns = @JoinColumn(
name = "role_id", referencedColumnName = "id"
)
)
private Set<Role> roles = new HashSet<>();
}
Role.java
package com.springdatajpa.springboot.entity;
import lombok.Getter;
import lombok.Setter;
import jakarta.persistence.*;
import java.util.HashSet;
import java.util.Set;
@Getter
@Setter
@Entity
@Table(name = "roles")
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String name;
@ManyToMany(cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
}, fetch = FetchType.EAGER,
mappedBy = "roles")
private Set<User> users = new HashSet<>();
}
5. Create Spring Data JPA Repositories
Next, let's create Spring Data JPA repositories to access the User and Role entities from the database.
The JpaRepository interface defines methods for all the CRUD operations on the entity, and a default implementation of the JpaRepository called SimpleJpaRepository.
Let's create a repository package inside a base package "net.javaguides.springdatarest".
Within the repository package, create UserRepository and RoleRepository interfaces with the following content:
Next, let's create Spring Data JPA repositories to access the User and Role entities from the database.
The JpaRepository interface defines methods for all the CRUD operations on the entity, and a default implementation of the JpaRepository called SimpleJpaRepository.
UserRepository.java
package com.springdatajpa.springboot.repository;
import com.springdatajpa.springboot.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {
}
RoleRepository.java
package com.springdatajpa.springboot.repository;
import com.springdatajpa.springboot.entity.Role;
import org.springframework.data.jpa.repository.JpaRepository;
public interface RoleRepository extends JpaRepository<Role, Long> {
}
6. Testing Many to Many Bidirectional Mapping
Let's write the JUnit tests to test many-to-many Bidirectional mapping using Spring Data JPA:
package com.springdatajpa.springboot.repository;
import com.springdatajpa.springboot.entity.Role;
import com.springdatajpa.springboot.entity.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
public class ManyToManyBidirectionalTest {
@Autowired
private RoleRepository roleRepository;
@Test
void saveRole(){
User user = new User();
user.setFirstName("ramesh");
user.setLastName("fadatare");
user.setEmail("ramesh@gmail.com");
user.setPassword("secrete");
User admin = new User();
admin.setFirstName("admin");
admin.setLastName("admin");
admin.setEmail("admin@gmail.com");
admin.setPassword("admin");
Role roleAdmin = new Role();
roleAdmin.setName("ROLE_ADMIN");
roleAdmin.getUsers().add(user);
roleAdmin.getUsers().add(admin);
user.getRoles().add(roleAdmin);
admin.getRoles().add(roleAdmin);
roleRepository.save(roleAdmin);
}
@Test
void fetchRole(){
List<Role> roles = roleRepository.findAll();
roles.forEach((r) ->{
System.out.println(r.getName());
r.getUsers().forEach((u) ->{
System.out.println(u.getFirstName());
});
});
}
}
Save Role will also save associated users (Cascade. PERSIST):
@Test
void saveRole(){
User user = new User();
user.setFirstName("ramesh");
user.setLastName("fadatare");
user.setEmail("ramesh@gmail.com");
user.setPassword("secrete");
User admin = new User();
admin.setFirstName("admin");
admin.setLastName("admin");
admin.setEmail("admin@gmail.com");
admin.setPassword("admin");
Role roleAdmin = new Role();
roleAdmin.setName("ROLE_ADMIN");
roleAdmin.getUsers().add(user);
roleAdmin.getUsers().add(admin);
user.getRoles().add(roleAdmin);
admin.getRoles().add(roleAdmin);
roleRepository.save(roleAdmin);
}
Fetch Role will also fetch its associated user (Fetch type EAGER):
@Test
void fetchRole(){
List<Role> roles = roleRepository.findAll();
roles.forEach((r) ->{
System.out.println(r.getName());
r.getUsers().forEach((u) ->{
System.out.println(u.getFirstName());
});
});
}
thanks sir great example
ReplyDelete