Tuesday, May 29, 2018

Hibernate Mapping - OneToMany Unidirectional Relationship Using JPA + Springboot

Hibernate OneToMany Relationship is one of the most used relationship when we do coding l, as why i am saying this is that , most of the scenario and use cases have the situation where we have one entity related with many other entity.




before we start taking about OneToMany using JPA , would like to cover the question what is OnetoMany Relationship in Hibernate.
OneToMany Relationship : When one entity ( table) is assotiated with more than one other entity (tables)  , It is called OneToMany Mapping 
Mapping can be 
Unidirectional : One Way Directional
Bidirectional : Both Way Directional.

In this article we will see how we implement One To Many Mapping Unidirectional with JPA in Spring Boot.

Let start.

First we will discuss the Scenario then we will talk about the Solution.

#Scenario
We are having 2 entity as vendor and ratings , We need to establish a relationship between vendor and ratings as OneToMany Unidirectional




#Solution
In this use case ratings itself dont have any importance if there is no vendor associated with it , that means if we are deleting the vendors , ratings should also be deleted associated to particular vendor.
this is called as one to many unidirectional mapping.

Now let see the Implementation.

Implementation (You can download the project from GitHub)
We will have one Rest End point where we are saving the vendor along with the rating of the vendor.

We are using below dependencies
1) Spring Web ( For Rest APIs )
2) H2 Database ( For InMemory Database)
3) JPA ( As ORM )
* can see the pom.xml in above github link

We will first see the Models used here
Vendor.java

package com.programinjava.learn.model;

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

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;


@Entity
public class Vendor {
 
 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
 private Integer id;
 
 private String name;
 
 private String companyName;
 
// other attributes of vendors
 @OneToMany(cascade=CascadeType.ALL)
 @JoinColumn(name="vendor_id")
 private List<Rating> ratings = new ArrayList<>();

 public Integer getId() {
  return id;
 }

 public void setId(Integer id) {
  this.id = id;
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 public String getCompanyName() {
  return companyName;
 }

 public void setCompanyName(String companyName) {
  this.companyName = companyName;
 }

 public List<Rating> getRatings() {
  return ratings;
 }

 public void setRatings(List<Rating> ratings) {
  this.ratings = ratings;
 }
 
}
Now we will see the other entity used in this use case
Rating.java

package com.programinjava.learn.model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Rating {

 @Id
 @GeneratedValue(strategy=GenerationType.AUTO)
 private Integer id;
 
 private Integer rating;
 
 private String comment;

 public Rating() {
  // TODO Auto-generated constructor stub
 }

 public Integer getId() {
  return id;
 }

 public void setId(Integer id) {
  this.id = id;
 }

 public Integer getRating() {
  return rating;
 }

 public void setRating(Integer rating) {
  this.rating = rating;
 }

 public String getComment() {
  return comment;
 }

 public void setComment(String comment) {
  this.comment = comment;
 }
   
}
If we see the Database schema generated for the above entity.
Vendor Table

Rating Table

Now we will see the service Impl Class.
VendorServiceImpl.java
package com.programinjava.learn.service;

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

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

import com.programinjava.learn.model.Rating;
import com.programinjava.learn.model.Vendor;
import com.programinjava.learn.repository.VendorRepository;

@Service
public class VendorServiceImpl implements VendorService{

 @Autowired
 VendorRepository vendorRepository;
 
 @Override
 public int add(Vendor vendor) throws Exception {
  
  Vendor vendor1 =vendorRepository.save(vendor);
  if(vendor1 == null)
   throw new Exception("Vendor not saved");
  return vendor1.getId();
  
  
 }

 @Override
 public void getAll() {
  // TODO Auto-generated method stub
  
 }

 @Override
 public void provideRating(Rating rating, Integer vendorId) throws Exception {

  if(vendorId !=null)
  {
   Optional<Vendor> vendor1 =vendorRepository.findById(vendorId);
   if(vendor1 == null)
    throw new Exception("Vendor not found");
   Vendor ve =vendor1.get();
   ve.getRatings().add(rating);
  }
  
  
 }

}
VendorController.java

package com.programinjava.learn.controller;

import java.net.URI;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.util.UriTemplate;

import com.programinjava.learn.model.Vendor;
import com.programinjava.learn.service.VendorService;

@RestController
public class VendorController {
 
 @Autowired
 VendorService vendorService;
 
 @PostMapping("/vendor")
 public ResponseEntity<Void> addVendor(@RequestBody Vendor vendor,BindingResult errors , HttpServletRequest request){
  if(errors.hasErrors())
  {
   return ResponseEntity.badRequest().build();
  }
  try {
   Integer id =vendorService.add(vendor);
   URI location = new UriTemplate(request.getRequestURI() + "/{id}").expand(id);
   return ResponseEntity.created(location).build();
   
  } catch (Exception e) {
   // TODO Auto-generated catch block
   return ResponseEntity.badRequest().build();   
  }
  
 }
 
 @GetMapping("/ping")
 public String ping() {
  return "Pong";
 }
 
 
 

}
Now when we see the Rest Endpoint Exposed is http://localhost/vendor ( which is post type )
We will use POSTMAN to hit the rest endpoint with below RequestBody
{
  "name": "vendor1",
  "companyName": "programinjava",
  "ratings": [
    {
      "rating": 4,
      "comment": "the vendor is ok ok "
    }
  ]
}

Important Things :
  • The Rating table don't have any vendor_id column defination ( if you have checked ).
  • If Vendor is deleted , the ratings of the vendor will also be deleted from the table.
  • We can fetch the rating wrt vendor but we can't fetch the vendor wrt rating as it is Unidirectional Mapping.
I hope this article will help you in understanding OneToMany relationship in hibernate using spring boot and JPA.



Thanks for reading


0 comments:

Post a Comment