Categories: Uncategorised

Spring Data JPA many to one mapping & Integration test

In this blog we will see Spring Data JPA many to one relationship example and also how to write integration test for the same.

In Spring Data JPA, the “Many-to-One” relationship is used to establish an association between two entities where multiple instances of one entity are associated with a single instance of another entity.

To start with lets create the project with the shown dependencies

To describe the relationship create two entity classes, one representing the “many” side and the other representing the “one” side of the relationship.

@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@Table(name="Orders")
@Builder
public class Order { 
 @Id
 @GeneratedValue(strategy = GenerationType.IDENTITY)
 int orderId; 
 int qty; 
 @ManyToOne
 @JoinColumn(name = "productId")
 private Product product;
}

@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Product {
 @Id
 @GeneratedValue(strategy = GenerationType.IDENTITY)
 int productId; 
 String productName;
 
}

In the Order entity, the @ManyToOne annotation is used to define the many-to-one relationship. The @JoinColumn annotation specifies the column that will hold the foreign key relationship.

Define Spring Data JPA repository interfaces for both entities

@Repository
public interface OrdersRepository extends JpaRepository<Order, Integer>{

 List<Order> findAllByProduct(Product product);

}
@Repository
public interface ProductsRepository extends JpaRepository<Product, Integer>{

}

To implement the entity relationship define below two API’s

i) add a product

ii) order a single product

Also define another API to get the total sales of a product

@RestController
public class ProductsalesController {

 @Autowired
 ProductsalesService service;

 @Autowired
 ProductsRepository prodRepo;

 @PostMapping("/product")
 public Product addProduct(@RequestBody Product product) {
  return service.addProduct(product);
 }

 @PostMapping("/order/{productId}")
 public Order createOrder(@PathVariable int productId, @RequestBody Order order) throws Exception {
  Optional<Product> prod = prodRepo.findById(productId);
  if (prod.isPresent()) {
   Product product = prod.get();
   order.setProduct(product);
   return service.createOrder(order);
  } else {
   throw new ProductNotFoundException("Order failed.Product not found", HttpStatus.NOT_FOUND.value());
  }

 }

 @GetMapping("/productsales/{productId}")
 public int getSalesForProduct(@PathVariable int productId) {
  return service.getSalesForProduct(productId);
 }

 @ExceptionHandler(ProductNotFoundException.class)
 @ResponseStatus(code = HttpStatus.NOT_FOUND)
 public ResponseEntity<String> handleProductNotFoundException(ProductNotFoundException exception) {
  return ResponseEntity.status(HttpStatus.NOT_FOUND).body(exception.getMessage());
 }
}

Configure Spring Boot to use postgreSQL

spring.datasource.url=jdbc:postgresql://localhost:5432/productsales
spring.datasource.username=${USERNAME}
spring.datasource.password=${PASSWORD}
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto = update

Service Implementation:

@Service
@NoArgsConstructor
@AllArgsConstructor
public class ProductsalesServiceImpl implements ProductsalesService{

 @Autowired
 ProductsRepository productRepo;
 
 @Autowired
 OrdersRepository orderRepo;
 
 public Product addProduct(Product product) {
  return productRepo.save(product);
 }

 @Override
 public Order createOrder(Order order) {
  return orderRepo.save(order);
 }

 @Override
 public int getSalesForProduct(int productId) {
  Optional<Product> prod = productRepo.findById(productId);
  int totalSales =0;
  List<Order> orders = orderRepo.findAllByProduct(prod.get());  
  for (Order order : orders) {
   
   totalSales = totalSales+order.getQty();
   
  }  
  return totalSales;  
 }
}

Testing the API using postman:

Testing Spring Boot controllers is an essential part of ensuring your application’s functionality and reliability. We will see a basic overview of how to write integration tests for Spring Boot controllers using the JUnit and Mockito frameworks.

@SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
@ActiveProfiles(value = "test")
@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class})
public class ProductsalesControllerTest {

 @Autowired
 private TestRestTemplate restTemplate;

 @MockBean 
 OrdersRepository orderRepo;

 @MockBean 
 ProductsRepository productRepo;

 @Autowired
 ProductsalesService svc;
 
 @Test
 public void testGetSalesForProduct() throws URISyntaxException {

  final String baseUrl = "/productsales/2";

  Optional<Product> prod = Optional.ofNullable(Product.builder().productId(1).productName("mobile").build());

  Order order1 = Order.builder().orderId(1).product(prod.get()).qty(5).build();
  Order order2= Order.builder().orderId(2).product(prod.get()).qty(5).build();

  List<Order> orders = new ArrayList<>();

  orders.add(order1);
  orders.add(order2);

  when(productRepo.findById(any())).thenReturn(prod);

  when(orderRepo.findAllByProduct(any())).thenReturn(orders);

  ResponseEntity<Integer> result = this.restTemplate.getForEntity(baseUrl, Integer.class);

  Assertions.assertEquals(200, result.getStatusCode().value());

  Assertions.assertEquals(10, result.getBody().intValue());
 }

}

For code please head to https://github.com/MMahendravarman/Springboot_Examples

mahendravarman.m@gmail.com

Recent Posts

Spring Webflux Functional Endpoint – File Upload

In this blog using the Spring WebFlux module, we are going to leverage the functional…

9 months ago

Serverless Functions with Spring Cloud Function, AWS Lambda

Spring Cloud Function is a project within the Spring ecosystem that allows developers to build…

9 months ago

Spring Boot + RabbitMQ – Decoupling Microservices Communication

RabbitMQ is an open-source message broker software that implements the Advanced Message Queuing Protocol (AMQP).…

9 months ago

Spring Integration – Sending files over SFTP

Spring Integration is a powerful extension of the Spring Framework designed to support the implementation…

9 months ago

Spring Cloud Config Client

The Spring Cloud Config Client is a component of the Spring Cloud framework that enables…

10 months ago

Handling CSV in Python

In Python, handling CSV (Comma Separated Values) files is easy using the built-in csv module.…

10 months ago