Many To One(Uni-directional) Relational Mapping with Spring Boot + Spring Data JPA + H2 Database

In this tutorial , we will see Many To One mapping of two entities using Spring Boot and Spring Data JPA using H2 database.

GitHub Link 

Tools:

  • Spring Boot
  • Spring Data JPA
  • H2 Database
  • IntelliJ IDEA
  • Maven

We have two entities Student and Department. Many students are part of one Department (Many To One).

This is called Many To One mapping between two entities. For each of this entity, table will be created in database. So there will be two tables created in database.

create table address (id bigint generated by default as identity, name varchar(255), primary key (id));
create table student (id bigint generated by default as identity, mobile integer, name varchar(255), address_id bigint, primary key (id));
alter table student add constraint FKcaf6ht0hfw93lwc13ny0sdmvo foreign key (address_id) references address(id);

Each table has primary key as ID . Two tables has Many To One relationship between them as each department has many students in them.

STUDENT table has foreign key as DEPT_ID in it. So STUDENT is a child table and DEPARTMENT table is parent table in this relationship. FOREIGN KEY constraint adds below restrictions –

  1. We can’t add records in child table if there is no entry in parent table. Ex. You can’t add department ID reference in STUDENT table if department ID is not present in DEPARTMENT table.
  2. You can’t delete the records from parent table unless corresponding references are deleted from child table . Ex. You can’t delete the entry
    DEPARTMENT table unless corresponding students from STUDENT table are deleted . You can apply ON_DELETE_CASCADE with foreign key constraint if you want to delete students from STUDENT table automatically when department is deleted.
  3. If you want to insert a student into STUDENT table then corresponding department should already be present in DEPARTMENT table.
  4. When any department is updated in DEPARTMENT table then child table will also see the updated reference from parent table

Now we will see how can we form this relationship using Spring data JPA entities.

Step 1: Define all the dependencies required for this project

<?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 http://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.1.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.myjavablog</groupId>
<artifactId>springboot-jpa-one-to-many-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-jpa-one-to-many-demo</name>
<description>Demo project for Spring Boot</description>
<pre><code><properties>
    <java.version>1.8</java.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.apache.tomcat</groupId>
                <artifactId>tomcat-jdbc</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <!--<scope>runtime</scope>-->
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <!-- https://mvnrepository.com/artifact/colt/colt -->
    <dependency>
        <groupId>colt</groupId>
        <artifactId>colt</artifactId>
        <version>1.2.0</version>
    </dependency>

</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build></code></pre>
</project>

spring-boot-starter-data-jpa – This jar is used to connect to database .It also has a support to provide different JPA implementations to interact with the database like Hibernate, JPA Repository, CRUD Repository etc.

h2 – Its used to create H2 database when the spring boot application boots up. Spring boot will read the database configuration from application.properties file and creates a DataSource out of it.

Step 2: Define the Model/Entity classes

Student.java

package com.myjavablog.model;

import org.springframework.stereotype.Repository;

import javax.annotation.Generated;
import javax.persistence.*;
import java.util.Optional;

@Entity
@Table(name = "STUDENT")
public class Student {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column
    private String name;

    @Column
    private int mobile;

    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "DEPT_ID")
    private Department department;

    public Long getId() {

        return id;
    }

    public void setId(Long id)
    {
        this.id = id;
    }

    public String getName() {

        return name;
    }

    public void setName(String name) {

        this.name = name;
    }

    public int getMobile() {

        return mobile;
    }

    public void setMobile(int mobile) {

        this.mobile = mobile;
    }

    public Department getDepartment() {

        return department;
    }

    public void setDepartment(Department department) {
        this.department = department;
    }
}

Department.java

package com.myjavablog.model;

import javax.persistence.*;
import java.util.List;

@Entity
@Table(name = "DEPARTMENT")
public class Department {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column
private String name;

public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}
}

Below are the Annotations used while creating the entity classes –

Spring Data JPA Annotations –

  • @Entity – This annotation marks the class annotations.
  • @Table – This annotation creates table in database.
  • @Id – It creates primary key in table.
  • @GeneratedValue – It defines primary key generation strategy like AUTO,IDENTITY,SEQUENCE etc.
  • @Column It defines column property for table.
  • @ManyToOne – This annotation creates Many to One relationship between Student and Department entities. The cascade property (CascadeType.ALL) defines what should happen with child table records when something happens with parent table records. On DELETE, UPDATE , INSERT operations in parent table child table should also be affected. Only @ManyToOne annotation is enough to form one-to-many relationaship. This annotation is generally used in child entity to form Unidirectional relational mapping.
  • @JoinColumn – You can define column which creates foreign key in a table. In our example, DEPT_ID is a foreign key in STUDENT table which references to ID in DEPARTMENT table.

Step 3: Create the JPA repositories to query STUDENT and DEPARTMENT tables

StudentRepository and AddressRepository implemets JpaRepository which has methods to perform all CRUD operations. It has methods like save(), find(), delete(),exists(),count() to perform database operations.

package com.myjavablog.dao;

import com.myjavablog.model.Student;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface StudentRepository extends JpaRepository<Student, Long> {
public Student findByName(String name);
}

package com.myjavablog.dao;

import com.myjavablog.model.Address;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface AddressRepository extends JpaRepository<Address, Long>{
}

Step 4: Create the class BeanConfig to configure the bean for H2 database

This class creates a bean ServletRegistrationBean and autowires it to spring container. This bean actually required to access H2 database from console through browser.

package com.myjavablog;

import org.h2.server.web.WebServlet;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class BeanConfig {
@Bean
ServletRegistrationBean h2servletRegistration() {
    ServletRegistrationBean registrationBean = new ServletRegistrationBean(new WebServlet());
    registrationBean.addUrlMappings("/console/*");
    return registrationBean;
}
}

Step 5: Last but not the least, You need to define application properties.

#DATASOURCE (DataSourceAutoConfiguration & #DataSourceProperties)
spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.username=sa
spring.datasource.password=
#Hibernate
#The SQL dialect makes Hibernate generate better SQL for the chosen #database
spring.jpa.properties.hibernate.dialect =org.hibernate.dialect.H2Dialect
spring.datasource.driverClassName=org.h2.Driver
#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
server.port=8082
server.error.whitelabel.enabled=false

Step 6: Create the spring boot main file

package com.myjavablog;

import com.myjavablog.dao.DepartmentRepository;
import com.myjavablog.dao.StudentRepository;
import com.myjavablog.model.Department;
import com.myjavablog.model.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

import java.util.Arrays;

@SpringBootApplication
public class SpringbootJpaOneToManyDemoApplication implements CommandLineRunner {
@Autowired
private DepartmentRepository departmentRepository;

@Autowired
private StudentRepository studentRepository;

public static void main(String[] args) {

    SpringApplication.run(SpringbootJpaOneToManyDemoApplication.class, args);
}

@Override
public void run(String... args) throws Exception {
//Unidirectional Mapping
	Department department = new Department();
	department.setName("COMPUTER");
        departmentRepository.save(department);

	Student student = new Student();
		student.setDepartment(departmentRepository.findDepartmentByName("COMPUTER"));
		student.setName("Anup");
		student.setMobile(989911);
		Student student1 = new Student();
		student1.setDepartment(departmentRepository.findDepartmentByName("IT"));
		student1.setName("John");
		student1.setMobile(89774);
		studentRepository.saveAll(Arrays.asList(student,student1));
}
}

Step 7: Now run the application

Run the application as a java application or as spring boot application spring-boot:run

Once you run the application records will be inserted to tables as below –

Step 8: This application also has REST endpoints to expose the services as below –

Save department –

Add students under created department –

We can check database entries to cross verify –

Leave a Comment

Bitnami