Spring JPA Hibernate One to Many Relationship – SpringBoot + MySQL

Spring JPA Hibernate One to Many Relationship – SpringBoot + MySQL

This tutorial will guide you through the steps of configuring Spring JPA One to Many relationship with Spring Boot and MySql.

Related articles:
Spring JPA – Many to Many relationship
How to configure Spring JPA One to One Relationship – SpringBoot
Spring Data Rest – JPA One-to-Many relational entities | SpringBoot + MySql + HAL Browser
Kotlin SpringJPA Hibernate One-To-Many relationship


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

II. Practice – Spring JPA One to Many Relationship

Step to do
– Create SpringBoot project
– Create Models
– Create JPA Repositories
– Configure Datasource & Spring JPA
– Implement a test Client
– Run & Check results

1. Create SpringBoot project

– Using SpringToolSuite, create a SpringBoot project. Then add needed 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.json</groupId>
	<artifactId>json</artifactId>
</dependency>

2. Create Models

2 Entities Company and Product that having One-to-Many relationship:

Spring Jpa One To Many Relationship

2.1 Company entity


package com.javasampleapproach.jpa.one2many.model;

import java.util.Set;

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

import org.json.JSONArray;
import org.json.JSONObject;

@Entity
@Table(name="company")
public class Company {
	@Id
    @GeneratedValue(strategy = GenerationType.AUTO)
	private int id;
    private String name;
    
    @OneToMany(mappedBy = "company", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private Set products;
    
    public Company(){
    }
    
    public Company(String name){
    	this.name = name;
    }
    
    // name
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    // products
    public void setProducts(Set products){
    	this.products = products;
    }
    
    public Set getProducts(){
    	return this.products;
    }
    
    public String toString(){
    	String info = "";
        JSONObject jsonInfo = new JSONObject();
        jsonInfo.put("name",this.name);
        
        JSONArray productArray = new JSONArray();
        if(this.products != null){
            this.products.forEach(product->{
                JSONObject subJson = new JSONObject();
                subJson.put("name", product.getName());
                productArray.put(subJson);
            });
        }
        jsonInfo.put("products", productArray);
        info = jsonInfo.toString();
        return info;
    }
}

2.2 Product entity


package com.javasampleapproach.jpa.one2many.model;

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

import org.json.JSONObject;

@Entity
@Table(name="product")
public class Product {
	
	@Id
    @GeneratedValue(strategy = GenerationType.AUTO)
	private int id;
    private String name;
    
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "company_id")
    private Company company;
    
    public Product(){
    }
    
    public Product(String name, Company company){
    	this.name = name;
    	this.company = company;
    }
    
    // name
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    // products
    public void setCompany(Company company){
    	this.company = company;
    }
    
    public Company getCompany(){
    	return this.company;
    }
    
    public String toString(){
    	String info = "";
    	
        JSONObject jsonInfo = new JSONObject();
        jsonInfo.put("name",this.name);
        
        JSONObject companyObj = new JSONObject();
        companyObj.put("name", this.company.getName());
        jsonInfo.put("company", companyObj);
        
        info = jsonInfo.toString();
        return info;
    }
}

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

3. Create JPA Repositories

Create 2 interface repositories by extends JpaRepository:
CompanyRepository.java


package com.javasampleapproach.jpa.one2many.repository;

import org.springframework.data.jpa.repository.JpaRepository;

import com.javasampleapproach.jpa.one2many.model.Company;

public interface CompanyRepository extends JpaRepository{
}

ProductRepository.java


package com.javasampleapproach.jpa.one2many.repository;

import org.springframework.data.jpa.repository.JpaRepository;

import com.javasampleapproach.jpa.one2many.model.Product;

public interface ProductRepository extends JpaRepository{
}

4. Configure datasource & Spring JPA

Open application.properties, configure spring.datasource & spring.jpa:


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

5. Implement a test Client

Use 2 repository: CompanyRepository & ProductRepository


@Autowired
CompanyRepository companyRepository;
 
@Autowired
ProductRepository productRepository;

Implement 3 functions:
clearData() is used to empty 2 tables company & product
saveData() is used to persist entities (Company & Product) to database
showData() is used to load all records (Company & Product) and show all on console.

For saveData(), we have to 2 approach:
-> saveDataWithApproach1(): saving Company objects that include Product list.
-> saveDataWithApproach2(): firstly persist Company entities(not include Product list). Then store Products with the persisted companies.

Full SourceCode:


package com.javasampleapproach.jpa.one2many;

import java.util.HashSet;
import java.util.List;

import javax.transaction.Transactional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import com.javasampleapproach.jpa.one2many.model.Company;
import com.javasampleapproach.jpa.one2many.model.Product;
import com.javasampleapproach.jpa.one2many.repository.CompanyRepository;
import com.javasampleapproach.jpa.one2many.repository.ProductRepository;


@SpringBootApplication
public class SpringJpaOneToManyRelationshipApplication implements CommandLineRunner{
    
    @Autowired
    CompanyRepository companyRepository;
     
    @Autowired
    ProductRepository productRepository;
 
    public static void main(String[] args) {
    	SpringApplication.run(SpringJpaOneToManyRelationshipApplication.class, args);
    }
 
    
    @Override
    public void run(String... arg0) throws Exception {
    	clearData();
    	saveData();
    	showData();
    }
    
    @Transactional
    private void clearData(){
    	companyRepository.deleteAll();
        productRepository.deleteAll();
    }
    
    @Transactional
    private void saveData(){
    	saveDataWithApproach1();
        // saveDataWithApproach2();
    }
    
    /**
     * Save Company objects that include Product list
     */
    private void saveDataWithApproach1(){
        Company apple = new Company("Apple");
        Company samsung = new Company("Samsung");
        
        Product iphone7 = new Product("Iphone 7", apple);
        Product iPadPro = new Product("IPadPro", apple);
        
        Product galaxyJ7 = new Product("GalaxyJ7", samsung);
        Product galaxyTabA = new Product("GalaxyTabA", samsung);
        
        apple.setProducts(new HashSet(){{
            add(iphone7);
            add(iPadPro);
        }});
        
        samsung.setProducts(new HashSet(){{
            add(galaxyJ7);
            add(galaxyTabA);
        }});
        
        // save companies
        companyRepository.save(apple);
        companyRepository.save(samsung);
    }
    
    
    /**
     * Save company first (not include product list). Then saving products which had attached a company for each.  
     */
    private void saveDataWithApproach2(){
    	
    	/*
    	 * Firstly persist companies (not include product list)
    	 */
        Company apple = new Company("Apple");
        Company samsung = new Company("Samsung");
        
        //save companies
        companyRepository.save(apple);
        companyRepository.save(samsung);
        
        /*
         * Then store products with had persisted companies.
         */
    	Product iphone7 = new Product("Iphone 7", apple);
        Product iPadPro = new Product("IPadPro", apple);
        
        Product galaxyJ7 = new Product("GalaxyJ7", samsung);
        Product galaxyTabA = new Product("GalaxyTabA", samsung);

        // save products
        productRepository.save(iphone7);
        productRepository.save(iPadPro);
        
        productRepository.save(galaxyJ7);
        productRepository.save(galaxyTabA);
    }
    
    @Transactional
    private void showData(){
    	// get All data
    	List companyLst = companyRepository.findAll();
        List productLst = productRepository.findAll();
         
        System.out.println("===================Product List:==================");
        productLst.forEach(System.out::println);
         
        System.out.println("===================Company List:==================");
        companyLst.forEach(System.out::println);
    }
    
}

6. Run & Check results

Build & Run the project with SpringBoot App mode.

– With Approach 1 for saving:
-> Hibernate Logs:


Hibernate: select company0_.id as id1_0_, company0_.name as name2_0_ from company company0_
Hibernate: select products0_.company_id as company_3_1_0_, products0_.id as id1_1_0_, products0_.id as id1_1_1_, products0_.company_id as company_3_1_1_, products0_.name as name2_1_1_ from product products0_ where products0_.company_id=?
Hibernate: select products0_.company_id as company_3_1_0_, products0_.id as id1_1_0_, products0_.id as id1_1_1_, products0_.company_id as company_3_1_1_, products0_.name as name2_1_1_ from product products0_ where products0_.company_id=?
Hibernate: delete from product where id=?
Hibernate: delete from product where id=?
Hibernate: delete from company where id=?
Hibernate: delete from product where id=?
Hibernate: delete from product where id=?
Hibernate: delete from company where id=?
Hibernate: select product0_.id as id1_1_, product0_.company_id as company_3_1_, product0_.name as name2_1_ from product product0_
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 (?, ?)
Hibernate: select company0_.id as id1_0_, company0_.name as name2_0_ from company company0_
Hibernate: select products0_.company_id as company_3_1_0_, products0_.id as id1_1_0_, products0_.id as id1_1_1_, products0_.company_id as company_3_1_1_, products0_.name as name2_1_1_ from product products0_ where products0_.company_id=?
Hibernate: select products0_.company_id as company_3_1_0_, products0_.id as id1_1_0_, products0_.id as id1_1_1_, products0_.company_id as company_3_1_1_, products0_.name as name2_1_1_ from product products0_ where products0_.company_id=?
Hibernate: select product0_.id as id1_1_, product0_.company_id as company_3_1_, product0_.name as name2_1_ from product product0_
Hibernate: select company0_.id as id1_0_0_, company0_.name as name2_0_0_, products1_.company_id as company_3_1_1_, products1_.id as id1_1_1_, products1_.id as id1_1_2_, products1_.company_id as company_3_1_2_, products1_.name as name2_1_2_ from company company0_ left outer join product products1_ on company0_.id=products1_.company_id where company0_.id=?
Hibernate: select company0_.id as id1_0_0_, company0_.name as name2_0_0_, products1_.company_id as company_3_1_1_, products1_.id as id1_1_1_, products1_.id as id1_1_2_, products1_.company_id as company_3_1_2_, products1_.name as name2_1_2_ from company company0_ left outer join product products1_ on company0_.id=products1_.company_id where company0_.id=?

– With Approach 2 for saving:
-> Hibernate Logs:


Hibernate: select company0_.id as id1_0_, company0_.name as name2_0_ from company company0_
Hibernate: select products0_.company_id as company_3_1_0_, products0_.id as id1_1_0_, products0_.id as id1_1_1_, products0_.company_id as company_3_1_1_, products0_.name as name2_1_1_ from product products0_ where products0_.company_id=?
Hibernate: select products0_.company_id as company_3_1_0_, products0_.id as id1_1_0_, products0_.id as id1_1_1_, products0_.company_id as company_3_1_1_, products0_.name as name2_1_1_ from product products0_ where products0_.company_id=?
Hibernate: delete from product where id=?
Hibernate: delete from product where id=?
Hibernate: delete from company where id=?
Hibernate: delete from product where id=?
Hibernate: delete from product where id=?
Hibernate: delete from company where id=?
Hibernate: select product0_.id as id1_1_, product0_.company_id as company_3_1_, product0_.name as name2_1_ from product product0_
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 (?, ?)
Hibernate: select company0_.id as id1_0_, company0_.name as name2_0_ from company company0_
Hibernate: select products0_.company_id as company_3_1_0_, products0_.id as id1_1_0_, products0_.id as id1_1_1_, products0_.company_id as company_3_1_1_, products0_.name as name2_1_1_ from product products0_ where products0_.company_id=?
Hibernate: select products0_.company_id as company_3_1_0_, products0_.id as id1_1_0_, products0_.id as id1_1_1_, products0_.company_id as company_3_1_1_, products0_.name as name2_1_1_ from product products0_ where products0_.company_id=?
Hibernate: select product0_.id as id1_1_, product0_.company_id as company_3_1_, product0_.name as name2_1_ from product product0_
Hibernate: select company0_.id as id1_0_0_, company0_.name as name2_0_0_, products1_.company_id as company_3_1_1_, products1_.id as id1_1_1_, products1_.id as id1_1_2_, products1_.company_id as company_3_1_2_, products1_.name as name2_1_2_ from company company0_ left outer join product products1_ on company0_.id=products1_.company_id where company0_.id=?
Hibernate: select company0_.id as id1_0_0_, company0_.name as name2_0_0_, products1_.company_id as company_3_1_1_, products1_.id as id1_1_1_, products1_.id as id1_1_2_, products1_.company_id as company_3_1_2_, products1_.name as name2_1_2_ from company company0_ left outer join product products1_ on company0_.id=products1_.company_id where company0_.id=?

-> Application’s Logs:


===================Product List:==================
{"name":"Iphone 7","company":{"name":"Apple"}}
{"name":"IPadPro","company":{"name":"Apple"}}
{"name":"GalaxyJ7","company":{"name":"Samsung"}}
{"name":"GalaxyTabA","company":{"name":"Samsung"}}
===================Company List:==================
{"name":"Apple","products":[{"name":"Iphone 7"},{"name":"IPadPro"}]}
{"name":"Samsung","products":[{"name":"GalaxyTabA"},{"name":"GalaxyJ7"}]}

Database data:
company table:

Spring Jpa One To Many Relationship - company results

product table:

Spring Jpa One To Many Relationship - product results

III. SourceCode

SpringJpaOneToManyRelationship



By grokonez | April 18, 2017.

Last updated on April 3, 2021.



Related Posts


6 thoughts on “Spring JPA Hibernate One to Many Relationship – SpringBoot + MySQL”

  1. Thanks for the tutorial. Its helped me a lot to learn what is Spring data jpa with spring boot.

    One issue i am facing is for the first time it is executing as expected. but when i am trying to run this example for the second time its is throwing an error saying “company table already exists”. ( i used MySQL)
    It is trying to create the tables. so i changed the properties like below and tried

    spring.jpa.generate-ddl=false
    spring.jpa.hibernate.ddl-auto=update

    still i am getting the same issue.

    could you please help me on this.

    1. Hello Jilani Pathan,

      spring.jpa.generate-ddl is used to generate table, if you set its value is false.
      Mean application will not create tables.
      -> The case spring.jpa.generate-ddl=false is used when you do not need create tables (tables had been created or you want to create it by manually).

      spring.jpa.hibernate.ddl-auto has a range values: {none, validate, update, create-drop}
      -> You need consider each case for using when development and production.

      About the above tutorial,
      spring.jpa.generate-ddl=true
      -> Mean Spring JPA will auto generate tables if needed.

      So we can see log for first running:

      2017-06-05 12:31:41.893  INFO 18136 --- [           main] rmationExtractorJdbcDatabaseMetaDataImpl : HHH000262: Table not found: company
      2017-06-05 12:31:41.894  INFO 18136 --- [           main] rmationExtractorJdbcDatabaseMetaDataImpl : HHH000262: Table not found: company
      2017-06-05 12:31:42.099  INFO 18136 --- [           main] rmationExtractorJdbcDatabaseMetaDataImpl : HHH000262: Table not found: product
      2017-06-05 12:31:42.100  INFO 18136 --- [           main] rmationExtractorJdbcDatabaseMetaDataImpl : HHH000262: Table not found: product
      2017-06-05 12:31:43.036  INFO 18136 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
      
      Table not found: company
      Table not found: product
      

      But the second time running, don’t see the log.

      We don’t set: spring.jpa.hibernate.ddl-auto means it has default value is none.

      -> So please check more!

      More About: “spring.jpa.hibernate.ddl-auto” = create-drop: It will create and drop tables when running your app,
      See logs:

      Hibernate: alter table product drop foreign key FKghawd5rtv8ok565nwpdyyuto9
      Hibernate: drop table if exists company
      Hibernate: drop table if exists product
      Hibernate: create table company (id integer not null auto_increment, name varchar(255), primary key (id))
      Hibernate: create table product (id integer not null auto_increment, name varchar(255), company_id integer, primary key (id))
      Hibernate: alter table product add constraint FKghawd5rtv8ok565nwpdyyuto9 foreign key (company_id) references company (id)
      

      Hope the info will be useful for you.

  2. How the main program is running and executing a set of methods and then closing on its own? I mean its not implementing any other DisposalBean?

    1. I got it. It was not a web project and hence the application was getting closed immediately after the execution of the methods in run.

  3. Hi

    Thanks for the tutorial, but I am getting an infinite loop while doing One to Many Mapping.
    Please find below details

    product category entity :

    @Entity
    @Table(name = "product_category")
    public class ProductCategory {
    	
    	@Id
    	@GeneratedValue(strategy=GenerationType.AUTO)
    	private int category_id;
    	private String category_name;
    	@OneToMany(mappedBy = "productCategory", cascade = CascadeType.ALL,fetch = FetchType.LAZY)
    	private Set products;
    	
    Product entity:
    
    @Entity
    @Table(name = "product")
    public class Product {
    
    	@Id
    	@GeneratedValue(strategy=GenerationType.AUTO)
    	private int product_id;
    	private String product_name;
    	private String product_description;
    	@ManyToOne(fetch = FetchType.LAZY)
    	@JoinColumn(name = "product_category_id")
    	private ProductCategory productCategory;
    
    Product Rest Controller:
    @RestController
    @RequestMapping("/product")
    public class ProductController {
    	
    	private static final Logger logger = LoggerFactory.getLogger(ProductController.class);
    	
    	@Autowired
    	private ProductRepository productRepository;
    	
    	@GetMapping("/getAll")
        public Iterable getAllProduct() {
    		logger.debug("inside getAll Product List Method");
            return productRepository.findAll();
        }
    

    Could you please help me to solve the same.
    Regards
    Pranoy

Got Something To Say:

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

*