Spring Boot Data JPA Unidirectional Many-To-One Relationship

Introduction

In unidirectional association, you will have navigation only in one direction, i.e, only one side of the association will have the reference to the other side. The one side of the association will implement one of the collection interfaces, if it has the reference to the other entity.

In many to one relationship, multiple source objects can have relationship with same target object. Let’s consider CD and Artist. So multiple CDs can be written by same Artist or multiple Artists can write the same CD. So I will create two tables CD and Artist in the database and you will see how many-to-one relationship works step by step.

Now I will apply many-to-one relationship. So multiple CDs can be written by same Artist.

Prerequisites

Java 1.8+ (11-16), Spring Boot 2.5.6, Maven 3.8.2

Project Setup

I am creating maven based project and you can use any IDE or tool for creating the Java based project. The name of the project is spring-jpa-unidirectional-manytoone. You can use the following pom.xml file for your 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>

	<groupId>com.roytuts</groupId>
	<artifactId>spring-jpa-unidirectional-manytoone</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<maven.compiler.source>16</maven.compiler.source>
		<maven.compiler.target>16</maven.compiler.target>
	</properties>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.5.6</version>
	</parent>

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

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

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>
	</dependencies>

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

application.properties

I am configuring datasource in src/main/resources/application.properties file with the following content:

The following datasource configuration is done in the src/main/resources/application.properties file:
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/roytuts
spring.datasource.username=root
spring.datasource.password=root
 
spring.jpa.show-sql = true
spring.jpa.properties.hibernate.format_sql=true
 
logging.level.org.hibernate.type.descriptor.sql=trace
 
spring.jpa.hibernate.ddl-auto = create
#spring.jpa.hibernate.ddl-auto = none

I have set the following properties so that Hibernate will create the required tables in MySQL server during application start up.

spring.jpa.hibernate.ddl-auto=create

I am logging SQL statement and formatting them for better reading in the console using the following key/value pairs:

spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
logging.level.org.hibernate.type.descriptor.sql=trace

Entity Class – Artist

The following entity class stores information about artist:

@Table
@Entity
public class Artist {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int artistId;

	@Column
	private String artistName;
}

Entity Class – Cd

The following entity class stores information about Cd.

@Table
@Entity
public class Cd {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int cdId;

	@Column
	private String cdTitle;

	@JoinColumn(name = "artistId")
	@ManyToOne(cascade = CascadeType.ALL, optional = false)
	private Artist artist;
}

The @ManyToOne annotation defines the relationship between entity classes or tables in database. This annotation will define many Cd can have single artist or a single artist can have many Cd. I have also specified the join column using @JoinColumn annotation which is a foreign key in the Cd table.

Repository

The repository interface extends JpaRepository from Spring framework to inherit the built-in functionalities.

public interface CdRepository extends JpaRepository<Cd, Integer> {

}

Service Class

The service class that processes business logic for the application.

@Service
public class ManyToOneService {

	@Autowired
	private CdRepository cdRepository;

	public void saveCdArtist(List<Cd> cds) {
		cdRepository.saveAll(cds);
	}

}

The above service code saves list of Cds into the database table.

Spring Boot Main Class

The spring boot main class is used to run the application.

@SpringBootApplication
public class ManyToOneUnidirectionalApp implements CommandLineRunner {

	@Autowired
	private ManyToOneService manyToOneService;

	public static void main(String[] args) {
		SpringApplication.run(ManyToOneUnidirectionalApp.class, args);
	}

	@Override
	public void run(String... args) throws Exception {
		// create Artist object
		Artist artist = new Artist();
		artist.setArtistName("Soumitra");

		// create CD
		Cd cd1 = new Cd();
		cd1.setCdTitle("Java");
		cd1.setArtist(artist);

		// create another CD
		Cd cd2 = new Cd();
		cd2.setCdTitle("PHP");
		cd2.setArtist(artist);

		manyToOneService.saveCdArtist(Arrays.asList(cd1, cd2));
	}

}

Testing the Many to One Application

Running the above main class will produce below log in the console. The log shows table creation query to data insertion into the tables.

Hibernate:
    
    drop table if exists artist
Hibernate:
    
    drop table if exists cd
Hibernate:
    
    create table artist (
       artist_id integer not null auto_increment,
        artist_name varchar(255),
        primary key (artist_id)
    ) engine=InnoDB
Hibernate:
    
    create table cd (
       cd_id integer not null auto_increment,
        cd_title varchar(255),
        artist_id integer not null,
        primary key (cd_id)
    ) engine=InnoDB
Hibernate:
    
    alter table cd
       add constraint FK9h0ltj552jugnhsskumg52wtm
       foreign key (artist_id)
       references artist (artist_id)
o.h.e.t.j.p.i.JtaPlatformInitiator       : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
c.r.s.j.u.m.ManyToOneUnidirectionalApp   : Started ManyToOneUnidirectionalApp in 8.136 seconds (JVM running for 9.088)
Hibernate:
    insert
    into
        artist
        (artist_name)
    values
        (?)
o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [VARCHAR] - [Soumitra]
Hibernate:
    insert
    into
        cd
        (artist_id, cd_title)
    values
        (?, ?)
o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [INTEGER] - [1]
o.h.type.descriptor.sql.BasicBinder      : binding parameter [2] as [VARCHAR] - [Java]
Hibernate:
    insert
    into
        cd
        (artist_id, cd_title)
    values
        (?, ?)
o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [INTEGER] - [1]
o.h.type.descriptor.sql.BasicBinder      : binding parameter [2] as [VARCHAR] - [PHP]

You will also find data have been saved into the corresponding tables:

spring data jpa many to one

Source Code

Download

Leave a Reply

Your email address will not be published. Required fields are marked *