We will learn how to implement bidirectional relationships in the One-To-Many association in this tutorial.
1. What is a bidirectional One-To-Many association
In a bidirectional relationship, we can obtain information about two related entities by querying each one separately. To put it another way, we can move from one entity to another and vice versa.
We looked at the example of One Owner as the author of Many Blogs in the previous tutorial on unidirectional relationships in the One-To-Many association. Now We will consider the relationship between the Owner and the Blog to demonstrate a bidirectional relationship.
Consider the following example of the Owner's association with the Blogs:
// Blog class
public class Blog {
private Int id;
…
private String title;
Private Owner owner;
…
}
// Owner class
public class Owner {
private Int id;
…
private List<Blog> blogs;
…
}
We simply added a reference of the Owner in the Blog class to maintain a bidirectional relationship, and because the Owner is already in a relationship with Blog, there is no change in the Owner entity. So now we can get an owner via the blog and also a list of an owner's blogs.
👉 Now there's a question: can we call the One-To-Many relationship a Many-To-One relationship? We obviously can. Consider the following examples in a different light: One owner wrote many blogs, and one publishing house published multiple (many) author books. As a result, many entities are related to one entity in a Many-To-One relationship.
2. Spring Boot Project
We will use Spring Initializr to create a new Spring Boot project, which will generate a basic structure for our Spring Boot project. The following dependencies have been added:
- Spring Boot DevTools - necessary development tools
- Spring Web - for Spring MVC and embedded Tomcat that will run the Spring Boot application
- Spring Data JPA - Java Persistence API
- MySQL Driver - JDBC driver for MySQL (for other DB you have to choose that dependency for that DB)
Then click on GENERATE to download the project zip file. Unzip the zip
file. Now import the project in Eclipse/Visual Studio Code as a Maven project.
3. Connect to the Database
We'll put the connection information in the application because we're using MySQL as our database. Hibernate will use this information to connect to the database as the application.properties file has a name/value pair. The connection information is described in the following snippet:
Here, we've set datasource.url to the URL of our JDBC connection. The database credentials are mentioned in datasource.user and datasource.password.
Spring Boot can gather the necessary information about the database from the connection URL, so it is not necessary to specify datasource.driver-class-name. However, we will be safer if we specify the driver-class-name.
When the application is running, jpa.show-sql displays Hibernate SQL queries in the console, jpa.hibernate.ddl-auto is set to update, which updates the database schema every time we restart the application, and hibernate.dialect indicates which database dialect we are using.
4. Entities
Make a package called entity and create a Blog class in it:
As previously discussed, we have created relationships with the Owner of the Blog entity by using the @ManyToOne annotation. We defined the owner_id column with @JoinColumn; this will actually point to the Owner.
Now create an Owner class in the entity package:
The Owner entity has a One-To-Many relationship with the Blog entity in this case. We used mappedBy with the name owner in the @OneToMany annotation - this actually refers to the owner property in the Blog entity. As a result, the owner is now referring to the blog entity.
And the relationship is as follows in the database:
5. Repositories
The repository in Spring Boot is the data access layer that allows us to interact with our real database for operations like insert, update, and delete using Spring Data JPA. We have significantly reduced the number of boilerplate codes required to perform database operations as our BlogRepository and OwnerRepository extend JpaRepository.
Make a package called repository and create a BlogRepository interface in it:
And create an OwnerRepository interface in the repository package:
6. Controllers
A controller is a class that has one or more public methods. Controllers are typically placed in the Controller directory. If a class is annotated with @Controller or @RestController in Spring Boot, it will serve as a controller, and its public methods will be exposed as HTTP endpoints if they are annotated with @PostMapping or @GetMapping.
As a result, an HTTP GET request to http://localhost:PORT/method-name invokes the @GetMapping method of the ExampleController class.
Create a package called controller and create the OwnerController class in it. The OwnerController consists of four methods:
- The first one is to save the new owner with blog details (/saveOwer).
- The second one is to save blog details to an existing owner (/saveBlog).
- The third one is to fetch owner details by id (/getOwner/{id}).
- The fourth is to get blog details by id (/getBlog/{id}).
We injected the OwnerRepository and BlogReository into our controller using the @Autowired annotation. The code is as follows:
7. Run the Project
To run the project in Visual Studio Code, follow these steps:
- Open SpringbootonetomanybiApplication.java.
- Click on Run to run the Java program.
To run the project in Eclipse, follow these steps:
- Right-click on SpringbootonetomanybiApplication.java.
- Then choose Run As, then click on Spring Boot App.
As a result, Hibernate has created two tables, OWNER_DETAILS and BLOG_DETAILS (table names are mentioned in respective POJOs), and will modify table BLOG_DETAILS to add a foreign key (owner_id) that will be referenced by OWNER_DETAILS (id).
Because we did not specify a port in the application.properties file, our project will run on port 8080, and the default URL to access any REST API in this project is http://localhost:8080/. Because our project runs on our local machine, we used localhost. If your project is running on a remote server or in EC2, you must use the remote server's or EC2's IP address or the elastic IP address.
8. Testing of the REST APIs
Now we will test those REST APIs that we have created in the
OwnerController.
👉 Create a New Owner
To create a new Owner along with his/her Blogs, we call the following URL
in the Postman:
http://localhost:8080/owner/saveOwner
Also, see the audit logs in the console:
According to the documentation, Hibernate first inserts the Owner into the OWNER_DETAILS table, followed by the Blogs into the BLOG_DETAILS table.
Let's take a look at the OWNER_DETAILS table in the database:
And the BLOG_DEAILS database table:
As we can see, the owner_id columns of the BLOG_DETAILS table contain the OWNER_DETAILS table's ID column value.
👉 Create a new Blog
To add blogs to an existing owner, we use Postman and call the following URL - we have passed the id as 1, which is the id of an existing owner:
http://localhost:8080/owner/saveBlog?id=1
Also, see the audit logs in the console:
As a result, Hibernate first retrieves the owner details using the provided id before saving the Blogs.
Let's take a look at the BLOG_DEAILS table in the database:
👉 Get Owner Details
In Postman, we call the following URL to get the owner's details as well as his or her blogs. We only have one owner with an id of 1, so we get the following information from him:
http://localhost:8080/owner/getOwner/1
👉 Fetch Blogs
This URL is used to retrieve information about a specific blog, including its owner's contact information. We will attempt to retrieve blog information for id value 2:
http://localhost:8080/owner/getBlog/2
9. Conclusion
Our lives are made easier by bidirectional relationships. Because we can easily navigate from one entity to another and vice versa if the entities are associated in One-To-One or One-To-Many relationships.
You can download the
source code.
Happy coding!!! 😊
Congratulations, very good post!!
ReplyDelete