Kotlin SpringJPA Hibernate One-To-Many relationship

In the tutorial, JavaSampleApproach will show you how to implement Kotlin SpringJPA Hibernate One-To-Many relationship application with SpringBoot.

Related posts:
Kotlin SpringJPA Many-To-Many relationship
How to configure Spring JPA One to Many Relationship – SpringBoot
Kotlin SpringJPA One-to-One relationship
Kotlin Spring MVC RequestMapping RESTful APIs with @GetMapping, @PostMapping, @PutMapping, @DeleteMapping | SpringBoot Example

I. Technologies

– Java 1.8
– Maven 3.3.9
– Spring Tool Suite – Version 3.8.1.RELEASE
– Spring Boot: 1.5.6.RELEASE
– MySQL Database
– Kotlin language

II. Practice

In the tutorial, We create a Kotlin SpringBoot project that have 2 entities Company and Product with One-To-Many relationship as below:

kotlin springjpa hibernate one-to-many - relationship uml

Project Structure:

kotlin springjpa hibernate one-to-many - project structure

Step to do:
– Create Kotlin SpringBoot project
– Create Kotlin data models
– Create Spring JPA repositories
– Implement RestController
– Run and check results

1. Create Kotlin SpringBoot project

Using SpringToolSuite to create a Kotlin SpringBoot project.

>>> More step details, you can follow below tutorial:

Then add needed dependencies:


[...]


<properties>
	<kotlin.compiler.incremental>true</kotlin.compiler.incremental>
	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
	<java.version>1.8</java.version>
	<kotlin.version>1.1.4</kotlin.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-web</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>
		<scope>runtime</scope>
	</dependency>
	
	<dependency>
		<groupId>org.jetbrains.kotlin</groupId>
		<artifactId>kotlin-stdlib-jre8</artifactId>
		<version>${kotlin.version}</version>
	</dependency>
	<dependency>
		<groupId>org.jetbrains.kotlin</groupId>
		<artifactId>kotlin-reflect</artifactId>
		<version>${kotlin.version}</version>
	</dependency>

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

[...]

2. Create Kotlin data models

Create 2 Kotlin data model:

Company.kt


package com.javasampleapproach.onetomany.model

import javax.persistence.CascadeType
import javax.persistence.Entity
import javax.persistence.GeneratedValue
import javax.persistence.GenerationType
import javax.persistence.FetchType
import javax.persistence.Id
import javax.persistence.OneToMany
import javax.persistence.Table


@Entity @Table(name = "company")
data class Company(
    var name: String = "",
    
    @OneToMany(mappedBy = "company", cascade = arrayOf(CascadeType.ALL), fetch = FetchType.EAGER)
    var products: List = emptyList(),
	
	
	@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
	var id: Long = 0
){
	override fun toString(): String{
		return "{name: ${this.name}, products: ${products.map { it->it.name }}}";
	}
}

Product.kt:


package com.javasampleapproach.onetomany.model

import javax.persistence.Entity
import javax.persistence.GeneratedValue
import javax.persistence.GenerationType
import javax.persistence.FetchType
import javax.persistence.Id
import javax.persistence.JoinColumn
import javax.persistence.ManyToOne
import javax.persistence.Table

@Entity @Table(name = "product")
data class Product(
    var name: String = "",

	@ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "company_id")
    var company: Company? = null,
	
	@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
	var id: Long = 0
){
	override fun toString(): String{
		return "{name: ${name}, company: ${company?.name}}"	
	}
}

3. Create Spring JPA repositories

Using interface JpaRepository to create 2 repositories:

interface CompanyRepository:


package com.javasampleapproach.onetomany.repo

import com.javasampleapproach.onetomany.model.Company
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Repository

@Repository
interface CompanyRepository : JpaRepository{
}

interface ProductRepository


package com.javasampleapproach.onetomany.repo

import com.javasampleapproach.onetomany.model.Product
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Repository

@Repository
interface ProductRepository : JpaRepository{
}

@Entity: Specifies that the class is an entity. This annotation is applied to the entity class.
@Id: Specifies the primary key of an entity.
@OneToMany: Defines a many-valued association with one-to-many multiplicity.
@ManyToOne: Defines a single-valued association to another entity class that has many-to-one multiplicity
@JoinColumn: Specifies a column for joining an entity association or element collection. If the JoinColumn annotation itself is defaulted, a single join column is assumed and the default values apply.

Now open application.properties file, add configuration:


spring.datasource.url=jdbc:mysql://localhost:3306/testdb
spring.datasource.username=root
spring.datasource.password=12345
 
spring.jpa.generate-ddl=true
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect

4. Implement RestController

Implement a Kotlin RestController RestAPIsController with 4 APIs:

– For saving entities, We implement 2 APIs with different approaches
-> /api/save/1: Firstly, do saving Company entities. Then do saving Product entities.
-> /api/save/2: Saving Company entities that had attached Product entities.

– For retrieve entities, We implement 2 APIs
-> /api/companies: fetch all Company entities from database.
-> /api/products: fetch all Product entities from database.


package com.javasampleapproach.onetomany.controller

import com.javasampleapproach.onetomany.model.Company
import com.javasampleapproach.onetomany.model.Product
import com.javasampleapproach.onetomany.repo.CompanyRepository
import com.javasampleapproach.onetomany.repo.ProductRepository
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController

@RestController
@RequestMapping("/api")
class RestAPIsController {
	
	@Autowired
	lateinit var companyRepository: CompanyRepository
	
	@Autowired
	lateinit var productRepository: ProductRepository

	@RequestMapping("/save/1")
	fun save(): String {
		// clear data
		productRepository.deleteAll()
		companyRepository.deleteAll()
		
		// prepare Company data
		val apple = Company("Apple")
		val samsung = Company("Samsung")
		
		// save list of companies to database
		companyRepository.save(setOf(apple, samsung))
		
		// prepare Product data
		val iphone7 = Product("Iphone 7", apple)
		val iPadPro = Product("IPadPro", apple)
		
		val galaxyJ7 = Product("GalaxyJ7", samsung)
		val galaxyTabA = Product("GalaxyTabA", samsung)
		
		// save list of products to database
		productRepository.save(setOf(iphone7, iPadPro, galaxyJ7, galaxyTabA))
		
		return "saving with approach 1 - done!"
	}
	
	@RequestMapping("/save/2")
	fun save2(): String {
		// clear data
		productRepository.deleteAll()
		companyRepository.deleteAll()
		
		// prepare Company data
		val apple = Company("Apple")
		val samsung = Company("Samsung")
		
		// prepare Product data
		val iphone7 = Product("Iphone 7", apple)
		val iPadPro = Product("IPadPro", apple)
		
		val galaxyJ7 = Product("GalaxyJ7", samsung)
		val galaxyTabA = Product("GalaxyTabA", samsung)
		
		// set products for companies
		apple.products = listOf(iphone7, iPadPro)
		samsung.products = listOf(galaxyJ7, galaxyTabA)
		
		// save list of companies to database
		companyRepository.save(listOf(apple, samsung))
		
		return "saving with approach 2 - done!"
	}
	
	@RequestMapping("/companies")
	fun findAllCompanies() : String {
		// fetch all companies from database
		val companies = companyRepository.findAll()
		
		// some processing for better String format on browser showing 
		var info : String = ""
		companies.forEach{
			info += it.toString() + "
" } return info } @RequestMapping("/products") fun findAllProducts() : String { // fetch all products from database val products = productRepository.findAll() // some processing codes for better String format on browser showing var info : String = "" products.forEach{ info += it.toString() + "
" } return info } }

5. Run and check results

Build and Run the Kotlin SpringBoot project by commanlines {mvn clean install, mvn spring-boot:run}.

– Make a saving request: http://localhost:8080/api/save/1

kotlin springjpa hibernate one-to-many - save 1

-> Hibernate’s Logs:


Hibernate: insert into company (name) values (?)
Hibernate: insert into company (name) values (?)
Hibernate: insert into product (company_id, name) values (?, ?)
Hibernate: insert into product (company_id, name) values (?, ?)
Hibernate: insert into product (company_id, name) values (?, ?)
Hibernate: insert into product (company_id, name) values (?, ?)

– You can try with another saving request: http://localhost:8080/api/save/2

kotlin springjpa one-to-many - save 2

-> Hibernate’s Logs:


Hibernate: insert into company (name) values (?)
Hibernate: insert into product (company_id, name) values (?, ?)
Hibernate: insert into product (company_id, name) values (?, ?)
Hibernate: insert into company (name) values (?)
Hibernate: insert into product (company_id, name) values (?, ?)
Hibernate: insert into product (company_id, name) values (?, ?)

-> Check database’s results:

kotlin springjpa one-to-many - db results

– Retrieve Company entities: http://localhost:8080/api/companies
-> Result:
kotlin springjpa one-to-many - retrieve companies

– Retrieve Product entities: http://localhost:8080/api/products
-> Results:

kotlin springjpa one-to-many - retrieve products

III. Sourcecode

KotlinSpringJPAOneToMany

One thought on “Kotlin SpringJPA Hibernate One-To-Many relationship”

Leave a Reply

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