JPA, Hibernate One to Many Mapping Example with Spring Boot and MySQL Database

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

  1. Spring boot 2+
  2. Hibernate 5+
  3. JDK 1.8+
  4. Maven 3+
  5. IDE - STS or Eclipse
  6. Spring Data JPA
  7. MySQL 5+

Development Steps

  1. Create Spring boot application
  2. Maven dependencies
  3. Project Structure
  4. Configuring the MySQL Database and Logging
  5. Defining the Domain Models
  6. Defining the Repositories
  7. 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.

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 -
Learn Spring Boot at https://www.javaguides.net/p/spring-boot-tutorial.html

Comments

  1. 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

Post a comment