SpringBoot JPA @OneToMany Mapping as name says we will see one to many mapping in SpringBoot and JPA.
First see the ER Diagram
SpringBoot JPA @OneToMany Mapping ER Diagram
Following is the Entity Relationship Diagram for user, user_mails and user_mobiles table.
One user can have multiple mail ids.
So this is a one to many relation.
similarly one user can have multiple mobile numbers.
This is also one to many mapping.
user’s id in user table is
Tools/Technology used
- Spring Boot 2.2
- JPA
- Eclipse IDE
- MySQL Database
SpringBoot JPA @OneToMany Mapping Directory Structure

To build project we used maven and included
- spring-boot-starter-web
- spring-boot-starter-data-jpa
- mysql-connector-java
You can also use spring Initializr to generate POM.xml
POM.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | <?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>2.7.2</version> <relativePath /> <!-- lookup parent from repository --> </parent> <groupId>com.ebhor</groupId> <artifactId>mvc</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>Spring Crud</name> <description>Spring CRUD Example</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> |
Application.properties file configuration
MySQL database is used.
Configuration with MySQL is as specified below
1 2 3 4 5 6 | spring.datasource.url=jdbc:mysql://localhost:3306/ebhor spring.datasource.username=root spring.datasource.password= spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.jpa.hibernate.ddl-auto=update spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect |
Entities
We have created three entity files User, UserMail and UserMobile.
Tables and columns are mapped in entity file.
User.java
To access multiple mail and mobile numbers user is mapped with UserMail and UserMobile entities.
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set userMails = new HashSet(0);
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set userMobiles = new HashSet(0);
@oneToMany mapping is used and few parameters are also used.
- mappedBy- a property name in userMails. Based on this property matching oneToMany mapping will be performed.
- cascade- Transactions that are performing on table will also perform on mapped table or not.
- fetch – specifies when to access mapped data from join table
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | package com.ebhor.crud.entity; import java.util.HashSet; import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.OneToMany; import javax.persistence.Table; import javax.persistence.Transient; @Entity @Table(name = "user") public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "id") private int id; @Column(name = "name", nullable = false) private String name; @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY) private Set<UserMail> userMails = new HashSet<UserMail>(0); @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY) private Set<UserMobile> userMobiles = new HashSet<UserMobile>(0); public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set<UserMail> getUserMails() { return userMails; } public void setUserMails(Set<UserMail> userMails) { this.userMails = userMails; } public User(int id, String name, Set<UserMail> userMails) { super(); this.id = id; this.name = name; this.userMails = userMails; } public User() { super(); } public Set<UserMobile> getUserMobiles() { return userMobiles; } public void setUserMobiles(Set<UserMobile> userMobiles) { this.userMobiles = userMobiles; } } |
UserMail.java
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "user_id")
@JsonIgnore
private User user;
Here User Object is mapped as Many to one.
The @JoinColumn specified based on which (user_mail) column it will perform join and fetch data.
@JsonIgnore- This will ignored the json result and prevent the loop.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | package com.ebhor.crud.entity; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; import com.fasterxml.jackson.annotation.JsonIgnore; @Entity @Table(name = "user_mails") public class UserMail { @Id @GeneratedValue(strategy = GenerationType.AUTO) private int id; @Column(name = "email", nullable = false) private String email; @ManyToOne(fetch = FetchType.LAZY, optional = false) @JoinColumn(name = "user_id") @JsonIgnore private User user; public UserMail() { super(); } public UserMail(int id, String email, User user) { super(); this.id = id; this.email = email; this.user = user; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } } |
UserMobiles
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | package com.ebhor.crud.entity; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; import org.hibernate.annotations.GenericGenerator; import com.fasterxml.jackson.annotation.JsonIgnore; @Entity @Table(name = "user_mobiles") public class UserMobile { @Id @GeneratedValue(strategy = GenerationType.AUTO) private int id; @Column(name = "mobile_no", nullable = false) private String mobileNo; @ManyToOne(fetch = FetchType.LAZY, optional = false) @JoinColumn(name = "user_id") @JsonIgnore private User user; public UserMobile() { } public UserMobile(int id, String mobileNo, User user) { super(); this.id = id; this.mobileNo = mobileNo; this.user = user; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getMobileNo() { return mobileNo; } public void setMobileNo(String mobileNo) { this.mobileNo = mobileNo; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } } |
UserDAO.java
UserDAO is responsible for fetching data from database.
1 2 3 4 5 6 7 | package com.ebhor.crud.dao; import org.springframework.data.repository.CrudRepository; import org.springframework.stereotype.Repository; import com.ebhor.crud.entity.User; @Repository public interface UserDAO extends CrudRepository<User, Integer>{ } |
UserService.java
1 2 3 4 5 6 7 8 9 10 11 12 13 | package com.ebhor.crud.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.ebhor.crud.dao.UserDAO; import com.ebhor.crud.entity.User; @Service public class UserService { @Autowired UserDAO dao; public Iterable<User> getUsers(){ return dao.findAll(); } } |
UserController.java
Here we have used RestController to show data on index position
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | package com.ebhor.crud.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import com.ebhor.crud.entity.User; import com.ebhor.crud.service.UserService; @RestController public class UserController { @Autowired UserService service; @GetMapping("/") public Iterable<User> users(){ return service.getUsers(); } } |
Result
On running above project we will get following data.

Read More