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

17 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

  4. Hmm it looks like your site ate my first comment
    (it was super long) so I guess I’ll just sum it up what I had written and say, I’m thoroughly enjoying your blog.
    I too am an aspiring blog blogger but I’m still new to everything.

    Do you have any helpful hints for novice blog writers? I’d certainly appreciate it.

  5. When I initially left a comment I seem to have clicked
    on the -Notify me when new comments are added- checkbox and from now on whenever a comment is added I recieve four emails with the same comment.
    Is there a way you can remove me from that service? Many thanks!

  6. Hi, I do think this is an excellent web site. I stumbledupon it 😉 I’m going to come back yet again since
    i have book marked it. Money and freedom is the best way to
    change, may you be rich and continue to help others.

  7. Nice weblog here! Additionally your website loads up fast!

    What host are you using? Can I am getting your affiliate link on your host?
    I desire my website loaded up as fast as yours lol

  8. Oh my goodness! Incredible article dude! Thank
    you so much, However I am going through issues with
    your RSS. I don’t understand the reason why I am unable to
    subscribe to it. Is there anyone else getting
    identical RSS issues? Anybody who knows the answer will you kindly respond?
    Thanx!!

Leave a Reply

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