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: