JPA One To Many example with Hibernate and Spring Boot
Tags: java, spring, todayilearned, webdev
Published: 2022-01-10 03:37:35

In this tutorial, I will show you how to implement Spring JPA One-To-Many mapping with Hibernate in a Spring Boot CRUD example using <code>@ManyToOne</code> annotation. You'll know:
<ul>
    	<li>How to configure Spring Data, JPA, Hibernate to work with Database</li>
    	<li>How to define Data Models and Repository interfaces for JPA One-To-Many relationship</li>
   	<li>Way to use Spring JPA to interact with Database for One-To-Many association</li>
	<li>Way to create Spring Rest Controller to process HTTP requests</li>
</ul>

Full Article: [https://www.bezkoder.com/jpa-one-to-many/](https://www.bezkoder.com/jpa-one-to-many/)

Read more [JPA Many to Many example](https://www.bezkoder.com/jpa-many-to-many/)

<h2><span id="Way">Appropriate way to implement JPA/Hibernate One To Many mapping</span></h2>
In a relational database, a One-to-Many relationship between table A and table B indicates that one row in table A links to many rows in table B, but one row in table B links to only one row in table A.

For example, you need to design data model for a Tutorial Blog in which <strong>One</strong> Tutorial has <strong>Many</strong> Comments. So this is a One-to-Many association.

You can map the child entities as a collection (List of <code>Comment</code>s) in the parent object (<code>Tutorial</code>), and JPA/Hibernate provides the <a href="https://docs.oracle.com/javaee/7/api/javax/persistence/OneToMany.html">@OneToMany</a> annotation for that case: only the parent-side defines the relationship. We call it unidirectional <code>@OneToMany</code> association.

Similarly, when only the child-side manage the relationship, we have unidirectional Many-to-One association with <a href="https://docs.oracle.com/javaee/7/api/javax/persistence/ManyToOne.html">@ManyToOne</a> annotation where the child (<code>Comment</code>) has an entity object reference to its parent entity (<code>Tutorial</code>) by mapping the Foreign Key column (<code>tutorial_id</code>).

The most appropriate way to implement JPA/Hibernate One To Many mapping is unidirectional Many-to-One association with <a href="https://docs.oracle.com/javaee/7/api/javax/persistence/ManyToOne.html">@ManyToOne</a>. You can read Vlad Mihalcea's <a href="https://vladmihalcea.com/the-best-way-to-map-a-onetomany-association-with-jpa-and-hibernate/">article</a> for more details.

<h2><span id="JPA_One_to_Many">JPA One To Many example</span></h2>
We're gonna create a Spring project from scratch, then we implement JPA/Hibernate One to Many Mapping with <code>tutorials</code> and <code>comments</code> table as following:


![jpa-one-to-many-diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4o3t19jjhmyuryiw766j.png)

We also write Rest Apis to perform CRUD operations on the Comment entities.

These are APIs that we need to provide:
<div class="table-responsive">
<table class="table table-hover  table table-hover" width="100%">
<thead>
<tr>
<th>Methods</th>
<th>Urls</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr>
<td>POST</td>
<td>/api/tutorials/:id/comments</td>
<td>create new Comment for a Tutorial</td>
</tr>
<tr>
<td>GET</td>
<td>/api/tutorials/:id/comments</td>
<td>retrieve all Comments of a Tutorial</td>
</tr>
<tr>
<td>GET</td>
<td>/api/comments/:id</td>
<td>retrieve a Comment by <code>:id</code></td>
</tr>
<tr>
<td>PUT</td>
<td>/api/comments/:id</td>
<td>update a Comment by <code>:id</code></td>
</tr>
<tr>
<td>DELETE</td>
<td>/api/comments/:id</td>
<td>delete a Comment by <code>:id</code></td>
</tr>
<tr>
<td>DELETE</td>
<td>/api/tutorials/:id</td>
<td>delete a Tutorial (and its Comments) by <code>:id</code></td>
</tr>
<tr>
<td>DELETE</td>
<td>/api/tutorials/:id/comments</td>
<td>delete all Comments of a Tutorial</td>
</tr>
</tbody>
</table>
</div>

Assume that we've had <strong>tutorials</strong> table like this:

![jpa-one-to-many-parent-table](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6qff41qmmvt0ugsxv00w.png)

Here are the example requests:

- Create new Comments: POST <code>/api/tutorials/[:id]/comments</code>

![jpa-one-to-many-example-create-child-records](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aiqvcwen538b7314np60.png)

<strong>comments</strong> table after that:

![jpa-one-to-many-child-table](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s62qallvz5nmnp4wr7gr.png)

- Retrieve all Comments of specific Tutorial: GET <code>/api/tutorials/[:id]/comments</code>

![jpa-one-to-many-example-spring-crud-retrieve](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/59hfpckp2idicw8k2s1f.png)

- Delete all Comments of specific Tutorial: DELETE <code>/api/tutorials/[:id]/comments</code>

![jpa-one-to-many-example-spring-crud-delete](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/coary1vd6nbw88qg8nq4.png)

Check the <strong>comment</strong> table, all Comments of Tutorial with id=2 were deleted:

![jpa-one-to-many-example-spring-crud-table-delete](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xptuxje1ns13ad8jio1v.png)

- Delete a Tutorial: DELETE <code>/api/tutorials/[:id]</code>

![jpa-one-to-many-example-spring-crud-delete-cascade](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/te5syo06mgnvhoxi7pmr.png)

![jpa-one-to-many-example-spring-crud-delete-parent-table](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gu9odpobpvofm9j9h8n9.png)

All Comments of the Tutorial with id=3 were <strong>CASCADE</strong> deleted automatically.

![jpa-one-to-many-example-spring-crud-delete-cascade-table](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/upnfokmwveq6cpsto10l.png)

Let's build our Spring Boot One to Many CRUD example.

<h2><span id="Spring_Boot_One_to_Many">Spring Boot One to Many example</span></h2>
<h3><span id="Technology">Technology</span></h3>
<ul>
    	<li>Java 8</li>
    	<li>Spring Boot 2.6.2 (with Spring Web MVC, Spring Data JPA)</li>
    	<li>PostgreSQL/MySQL</li>
    	<li>Maven 3.8.1</li>
</ul>

<h3><span id="Project_Structure">Project Structure</span></h3>

![jpa-one-to-many-example-hibernate-spring-boot-project-structure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xw9ii4dpfssuyu57v29h.png)

Let me explain it briefly.

– <code>Tutorial</code>, <code>Comment</code> data model class correspond to entity and table <em>tutorials</em>, <em>comments</em>.
– <code>TutorialRepository</code>, <code>CommentRepository</code> are interfaces that extends <a href="https://docs.spring.io/spring-data/jpa/docs/current/api/org/springframework/data/jpa/repository/JpaRepository.html">JpaRepository</a> for CRUD methods and custom finder methods. It will be autowired in <code>TutorialController</code>, <code>CommentController</code>.
– <code>TutorialController</code>, <code>CommentController</code> are <a href="https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/RestController.html">RestController</a>s which has request mapping methods for RESTful CRUD API requests.
– Configuration for Spring Datasource, JPA & Hibernate in <strong>application.properties</strong>.
– <strong>pom.xml</strong> contains dependencies for Spring Boot and MySQL/PostgreSQL/H2 database.

– About <strong>exception</strong> package, to keep this post straightforward, I won't explain it. For more details, you can read following tutorial:
<a href="https://www.bezkoder.com/spring-boot-restcontrolleradvice/">@RestControllerAdvice example in Spring Boot</a>

For step by step and Github, please visit:
[https://www.bezkoder.com/jpa-one-to-many/](https://www.bezkoder.com/jpa-one-to-many/)

You can apply this implementation in following tutorials:
- <a href="https://www.bezkoder.com/spring-boot-jpa-h2-example/">Spring JPA + H2 example</a>
- <a href="https://bezkoder.com/spring-boot-jpa-crud-rest-api/">Spring JPA + MySQL example</a>
- <a href="https://bezkoder.com/spring-boot-postgresql-example/">Spring JPA + PostgreSQL example</a>
- <a href="https://www.bezkoder.com/spring-boot-hibernate-oracle/">Spring JPA + Oracle example</a>
- <a href="https://www.bezkoder.com/spring-boot-sql-server/">Spring JPA + SQL Server example</a>

<h2><span id="Further_Reading">Further Reading</span></h2>
<ul>
	<li><a href="https://www.bezkoder.com/spring-boot-jwt-authentication/">Secure Spring Boot App with Spring Security & JWT Authentication</a></li>
	<li><a href="https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#reference">Spring Data JPA Reference Documentation</a></li>
	<li><a href="https://www.bezkoder.com/spring-boot-pagination-sorting-example/">Spring Boot Pagination and Sorting example</a></li>
</ul>

If you want to add Pagination to this Spring project, you can find the instruction at:
<a href="https://www.bezkoder.com/spring-boot-pagination-filter-jpa-pageable/">Spring Boot Pagination & Filter example | Spring JPA, Pageable</a>

To sort/order by multiple fields:
<a href="https://www.bezkoder.com/spring-data-sort-multiple-columns/">Spring Data JPA Sort/Order by multiple Columns | Spring Boot</a>

Handle Exception for this Rest APIs is necessary:
- <a href="https://www.bezkoder.com/spring-boot-controlleradvice-exceptionhandler/">Spring Boot @ControllerAdvice & @ExceptionHandler example</a>
- <a href="https://www.bezkoder.com/spring-boot-restcontrolleradvice/">@RestControllerAdvice example in Spring Boot</a>

Or way to write Unit Test for the JPA Repository:
<a href="https://www.bezkoder.com/spring-boot-unit-test-jpa-repo-datajpatest/">Spring Boot Unit Test for JPA Repository with @DataJpaTest</a>

You can also know:
- how to deploy this Spring Boot App on AWS (for free) with <a href="https://www.bezkoder.com/deploy-spring-boot-aws-eb/">this tutorial</a>.
- dockerize with <a href="https://www.bezkoder.com/docker-compose-spring-boot-mysql/">Docker Compose: Spring Boot and MySQL example</a>
- way to upload an Excel file and store the data in MySQL database with <a href="https://www.bezkoder.com/spring-boot-upload-excel-file-database/">this post</a>
- upload CSV file and store the data in MySQL with <a href="https://www.bezkoder.com/spring-boot-upload-csv-file/">this post</a>.