One To Many Bidirectional Mapping In Hibernate/JPA Annotation Example Using Spring Boot and Oracle

In this post, we will see One To Many Bidirectional Mapping In Hibernate/JPA Annotation Example Using Spring Boot and Oracle. One book can have many stories and many stories can be associated with one book.

Before going ahead, let’s see some points.

  • We have two entity Book.java and Story.java. Book and Story entity will have One To Many and Many To One Bidirectional mapping.
  • For this example, we are assuming One book can have many stories and many stories can be associated with one book.
  • We are going to use two annotations @OneToMany and @ManyToOne annotations for mapping.
  • We will not create a table explicitly, let’s hibernate do this job.

Note –  Default Fetch type in case of below annotations.

@OneToOne – Default fetch type is EAGER.
@OneToMany – Default fetch type is LAZY.
@ManyToOne – Default fetch type is EAGER.
@ManyToMany – Default fetch type is LAZY.

We are going to use Spring Boot, maven, embedded tomcat, postman, Eclipse and oracle database. Here we will have some rest endpoint which will be used to save and retrieve data in the database. After running the below example we will be able to save the Book and Story entity which is in @OneToMany and @ManyToOne relationship.

Rest endpoints for this example.

1. Save book(POST) – http://localhost:9091/book/savebook – Obserb in below response one book have many stories.

Request data

{
"bookName":"Premchand's stories"
}

 

Response Data

{
	"bookId": 1,
	"bookName": "Premchand's stories",
	"storyList": [{
			"storyId": 2,
			"storyName": "Push Ki Rat"
		},
		{
			"storyId": 3,
			"storyName": "Idgah"
		},
		{
			"storyId": 4,
			"storyName": "Story Of Two Oxes"
		}
	]
}

http://localhost:9091/book/savebook


 

One To Many Bidirectional Mapping In Hibernate/JPA Annotation Example Using Spring Boot and Oracle

 

2. Get all stories(GET) – http://localhost:9091/story/stories – Get all stories details. Obserb in below response data many stories have the same book.

[{
		"storyId": 2,
		"storyName": "Push Ki Rat",
		"book": {
			"bookId": 1,
			"bookName": "Premchand's stories"
		}
	},
	{
		"storyId": 3,
		"storyName": "Idgah",
		"book": {
			"bookId": 1,
			"bookName": "Premchand's stories"
		}
	},
	{
		"storyId": 4,
		"storyName": "Story Of Two Oxes",
		"book": {
			"bookId": 1,
			"bookName": "Premchand's stories"
		}
	}
]

 

3. Get book details(GET) –  http://localhost:9091/book/{bookId}

Database details.

Let’s see One To Many Bidirectional Mapping In Hibernate/JPA Annotation Example Using Spring Boot and Oracle from scratch.

Create a new maven project and open pom.xml and replace it with the below code.

<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>onetomanybidirectinalhibernatejpa</groupId>
	<artifactId>onetomanybidirectinalhibernatejpa</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>onetomanybidirectinalhibernatejpa</name>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.0.2.RELEASE</version>
	</parent>
	<dependencies>
		<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>com.oracle</groupId>
			<artifactId>ojdbc6</artifactId>
			<version>11.2.0.3</version>
		</dependency>

	</dependencies>

	<build>
		<finalName>${project.artifactId}</finalName>
		<plugins>

			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.1</version>
				<configuration>
					<fork>true</fork>
					<executable>C:\Program Files\Java\jdk1.8.0_131\bin\javac.exe</executable>
				</configuration>
			</plugin>


		</plugins>
	</build>
</project>

Note – In pom.xml we have defined javac.exe path in configuration tag. You need to change accordingly i.e where you have installed JDK.

If you see any error for oracle dependency then follow these steps. Let maven download all necessary jar. Once it is done we will able to see the maven dependency folder which contains different jar files. We can start writing our controller classes, ServiceImpl and Repository. The directory structure of the application looks as below.

One To Many Bidirectional Hibernate/Jpa Spring Boot

Book.java

package com.hibernatejpa.entity;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
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 com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonManagedReference;

@Entity
public class Book {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private int bookId;

	@Column(name = "book_name")
	private String bookName;

	@OneToMany(fetch = FetchType.EAGER, mappedBy="book", cascade = CascadeType.ALL)
	@JsonIgnoreProperties("book")
	private List<Story> storyList = new ArrayList<>();

	public int getBookId() {
		return bookId;
	}

	public void setBookId(int bookId) {
		this.bookId = bookId;
	}

	public String getBookName() {
		return bookName;
	}

	public void setBookName(String bookName) {
		this.bookName = bookName;
	}

	public List<Story> getStoryList() {
		return storyList;
	}

	public void setStoryList(List<Story> storyList) {
		this.storyList = storyList;
	}




	
	

}

Story.java

package com.hibernatejpa.entity;

import javax.persistence.CascadeType;
import javax.persistence.Column;
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 com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@Entity
public class Story {

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private int storyId;

	@Column(name = "story_name")
	private String storyName;

	@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
	@JoinColumn(name = "book_id",referencedColumnName="bookId")
	@JsonIgnoreProperties("storyList")
	private Book book;
	
	public int getStoryId() {
		return storyId;
	}

	public void setStoryId(int storyId) {
		this.storyId = storyId;
	}

	public String getStoryName() {
		return storyName;
	}

	public void setStoryName(String storyName) {
		this.storyName = storyName;
	}

	public Book getBook() {
		return book;
	}

	public void setBook(Book book) {
		this.book = book;
	}
	
	

}

Define the repository interface extending CrudRepository.


BookRepository.java

package com.hibernatejpa.repository;

import java.io.Serializable;

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

import com.hibernatejpa.entity.Book;
@Repository
public interface BookRepository extends CrudRepository<Book,Serializable> {
	public Book findByBookId(int bookId);
}

Define the Service interface.


BookService.java

package com.hibernatejpa.service;

import org.springframework.stereotype.Component;

import com.hibernatejpa.entity.Book;

@Component
public interface BookService {
	public Book saveBook(Book book);
	public Book findByBookId(int bookId);
}

StoryRepository.java

package com.hibernatejpa.repository;

import java.io.Serializable;

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import com.hibernatejpa.entity.Story;

@Repository
public interface StoryRepository extends CrudRepository<Story,Serializable>{
}

Define service implementation class.

BookServiceImpl.java

package com.hibernatejpa.impl;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.hibernatejpa.entity.Book;
import com.hibernatejpa.entity.Story;
import com.hibernatejpa.repository.BookRepository;
import com.hibernatejpa.repository.StoryRepository;
import com.hibernatejpa.service.BookService;

@Service("bookServiceImpl")
public class BookServiceImpl implements BookService {

	@Autowired
	private BookRepository bookRepository;
	
	@Autowired
	private StoryRepository storyrepository;

	public Book saveBook(Book book) {
		List<Story> storyList = new ArrayList<>();
		
		//create first story
		Story story1 = new Story();
		story1.setStoryName("Push Ki Rat");

		//create second story
		Story story2 = new Story();
		story2.setStoryName("Idgah");
		
		//create third story
		Story story3 = new Story();
		story3.setStoryName("Story Of Two Oxes");

		//add all story into storyList. Till here we have prepared data for OneToMany
		storyList.add(story1);
		storyList.add(story2);
		storyList.add(story3);
		
		//Prepare data for ManyToOne
		story1.setBook(book);
		story2.setBook(book);
		story3.setBook(book);
		
		book.setStoryList(storyList);
		book = bookRepository.save(book);
		
		return book;

	}

	public Book findByBookId(int bookId) {
		Book book = bookRepository.findByBookId(bookId);
		return book;
	}
}

Note – See here more about @Component, @Controller, @Service and @Repository annotations here.

BookController.java

package com.hibernatejpa.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import com.hibernatejpa.entity.Book;
import com.hibernatejpa.service.BookService;

@RestController
@RequestMapping(value = "/book")
public class BookController {

	@Autowired
	private BookService bookService;

	@RequestMapping(value = "/savebook", method = RequestMethod.POST)
	@ResponseBody
	public Book saveBook(@RequestBody Book book) {

		Book bookResponse = bookService.saveBook(book);
		return bookResponse;
	}

	@RequestMapping(value = "/{bookId}", method = RequestMethod.GET)
	@ResponseBody
	public Book getBookDetails(@PathVariable int bookId) {
		Book bookResponse = bookService.findByBookId(bookId);

		return bookResponse;
	}

}

StoryController.java

package com.hibernatejpa.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import com.hibernatejpa.entity.Story;
import com.hibernatejpa.repository.StoryRepository;
@RestController
@RequestMapping(value = "/story")
public class StoryController {
	
	@Autowired
	StoryRepository storyRepository;
	
	@ResponseBody
	@RequestMapping(value = "/stories")
	public List<Story> getBookDetails() {
		List<Story> storyresponse = (List<Story>) storyRepository.findAll();

		return storyresponse;
	}
}

JpaConfig.java

package com.hibernatejpa.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@Configuration
@EnableJpaRepositories(basePackages = "com.hibernatejpa.repository")
public class JpaConfig {

}

Define the SpringMain.java

package com.hibernatejpa.main;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan(basePackages="com.hibernatejpa.*")
@EntityScan("com.hibernatejpa.*")
public class SpringMain {
	public static void main(String[] args) {

        SpringApplication.run(SpringMain.class, args);
    }

}

And finally, we have an application.properties file where we have database details.

# Connection url for the database
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:XE
spring.datasource.username=SYSTEM
spring.datasource.password=oracle2
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
# Show or not log for each sql query
spring.jpa.show-sql = true
 
 
spring.jpa.hibernate.ddl-auto =create
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.Oracle10gDialect
 
server.port = 9091

Let’s run the SpringMain class and test the endpoints.

http://localhost:9091/book/savebook

One To Many Bidirectional Hibernate/Jpa Spring Boot

http://localhost:9091/story/stories

http://localhost:9091/book/{bookId}

One To Many Bidirectional Hibernate/Jpa Spring Boot

That’s all about One To Many Bidirectional Mapping In Hibernate/JPA Annotation Example Using Spring Boot and Oracle.

 

One to One Mapping Annotation Example in Hibernate/JPA using Spring Boot and Oracle.
One to One Bidirectional Mapping Example In Hibernate/JPA Using Spring Boot and Oracle.
One To Many Mapping Annotation Example In Hibernate/JPA Using Spring Boot And Oracle.
Many To One Unidirectional Mapping In Hibernate/JPA Annotation Example Using Spring Boot and Oracle.
Many To Many Mapping Annotation Example In Hibernate/JPA Using Spring Boot And Oracle.

 

@OneToMany Docs.

Summary – We have seen One To Many Bidirectional Mapping In Hibernate/JPA Annotation Example Using Spring Boot and Oracle.