In this tutorial, we will learn how to define a one-to-many unidirectional mapping between two entities using JPA and Hibernate.
For bidirectional one-to-many mapping, check out Spring Boot JPA/Hibernate One to Many Bidirectional Example Tutorial
We create a Spring boot project from the scratch and we will implement the one-to-many mapping between two entities using JPA and Hibernate. We will use a MySQL database to store and retrieve the data.
Learn Spring Boot at https://www.javaguides.net/p/spring-boot-tutorial.html
Overview
The one-to-many mapping means that one row in a table is mapped to multiple rows in another table.
We will implement one-to-many unidirectional mapping using @OneToMany and @JoinColumn JPA annotations.
Consider the following two tables - posts and comments of a Blog database schema where the posts table has a one-to-many relationship with the comments table:
Tools and Technologies used
- Spring boot 2+
- Hibernate 5+
- JDK 1.8+
- Maven 3+
- IDE - STS or Eclipse
- Spring Data JPA
- MySQL 5+
Development Steps
- Create Spring boot application
- Maven dependencies
- Project Structure
- Configuring the MySQL Database and Logging
- Defining the Domain Models
- Defining the Repositories
- Test One to Many Mapping
1. Create a Spring Boot Application
There are many ways to create a Spring Boot application. You can refer below articles to create a Spring Boot application.
>> Create Spring Boot Project With Spring Initializer
>> Create Spring Boot Project in Spring Tool Suite [STS]
>> Create Spring Boot Project in Spring Tool Suite [STS]
2. Maven dependencies
Let's review all maven dependencies in pom.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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath/>
<!-- lookup parent from repository -->
</parent>
<groupId>net.javaguides</groupId>
<artifactId>springboot-hibernate-one-many-mapping</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-hibernate-one-many-mapping</name>
<description>Demo project for Spring Boot Hibernate one to many mapping</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3. Project Structure
Let's refer below screenshot to create our Project packaging structure -
4. Configuring the MySQL Database and Logging
We’ll need to configure MySQL database URL, username, and password so that Spring can establish a connection with the database on startup. Open src/main/resources/application.properties and add the following properties to it:
# DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
spring.datasource.url=jdbc:mysql://localhost:3306/demo?useSSL=false&serverTimezone=UTC&useLegacyDatetimeCode=false
spring.datasource.username=root
spring.datasource.password=root
# Hibernate
# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect
# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto = update
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type=TRACE
Don’t forget to change the spring.datasource.username and spring.datasource.password as per your MySQL installation. Also, create a database named demo in MySQL before proceeding to the next section.
5. Defining the Domain Models
Let's define the domain models of our application - Post and Comment.
Post.java
package net.javaguides.springboot.entity;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
@Table(name = "posts")
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Column(name = "title")
private String title;
@Column(name = "description")
private String description;
@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "pc_fid", referencedColumnName = "id")
List < Comment > comments = new ArrayList < > ();
public Post() {
}
public Post(String title, String description) {
super();
this.title = title;
this.description = description;
}
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 String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public List < Comment > getComments() {
return comments;
}
public void setComments(List < Comment > comments) {
this.comments = comments;
}
}
Comment.java
package net.javaguides.springboot.entity;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "comments")
public class Comment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String text;
public Comment() {
}
public Comment(String text) {
super();
this.text = text;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
Let's understand the JPA annotations:
- @Table maps the entity with the table. If no @Table is defined, the default value is used: the class name of the entity.
- @Id declares the identifier property of the entity.
- @Column maps the entity's field with the table's column. If @Column is omitted, the default value is used: the field name of the entity.
- @OneToMany defines a one-to-many relationship between 2 entities.
- @JoinColumn indicates the entity is the owner of the relationship: the corresponding table has a column with a foreign key to the referenced table.
6. Defining the Repositories
Let's define the repositories for accessing the data from the database.
PostRepository.java
package net.javaguides.springboot.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import net.javaguides.springboot.entity.Post;
@Repository
public interface PostRepository extends JpaRepository<Post, Long>{
}
CommentRepository.java
package net.javaguides.springboot.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import net.javaguides.springboot.entity.Comment;
@Repository
public interface CommentRepository extends JpaRepository<Comment, Long>{
}
7. Test One to Many Mapping
Let’s now write some code to test our setup. Run this spring boot project and review the one-to-mapping between posts and comments tables in MySQL database:
package net.javaguides.springboot;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import net.javaguides.springboot.entity.Comment;
import net.javaguides.springboot.entity.Post;
import net.javaguides.springboot.repository.PostRepository;
@SpringBootApplication
public class SpringbootHibernateOneManyMappingApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(SpringbootHibernateOneManyMappingApplication.class, args);
}
@Autowired
private PostRepository postRepository;
@Override
public void run(String...args) throws Exception {
Post post = new Post("one to many mapping using JPA and hibernate", "one to many mapping using JPA and hibernate");
Comment comment1 = new Comment("Very useful");
Comment comment2 = new Comment("informative");
Comment comment3 = new Comment("Great post");
post.getComments().add(comment1);
post.getComments().add(comment2);
post.getComments().add(comment3);
this.postRepository.save(post);
}
}
Video Tutorial
This tutorial explained very well with demo in below YouTube video:
Conclusion
In this tutorial, we have seen how to define a one-to-many unidirectional mapping between two entities using JPA and Hibernate.
We have created a Spring boot project from the scratch and we have implemented the one-to-many mapping between two entities using JPA and Hibernate. We used a MySQL database to store and retrieve the data.
You might also be interested in checking out the following articles on JPA/Hibernate Mapping -
- Spring Boot + JPA/Hibernate One to One Mapping Example
- Spring Boot JPA/Hibernate One to Many Example Tutorial
- Spring Boot Hibernate Many to Many Example
Learn Spring Boot at https://www.javaguides.net/p/spring-boot-tutorial.html
Hello thank you for explanation it very helpful for us! I have a question, if I wantEd insert comments after post how can I do it?
ReplyDelete