In Many to
Many relationship, records in the first table are mapped to multiple rows in
the second table and similarly rows in the second table are mapped to multiple
rows in the first table.
For
example, Take two tables, employees and projects. An employee can work in one
or more projects and similarly a project can contain one or more employees.
We can
model this many to many relationship using a mapping table.
employees
Table
emp_id
|
first_name
|
last_name
|
projects
Table
pjt_id
|
project_name
|
Team_size
|
employee_project_mapping
table
emp_id
|
pjt_id
|
@Entity
@Table(name = "employees")
public class Employee {
@Id
@GeneratedValue
@Column(name = "emp_id")
private int id;
private String firstName;
private String lastName;
@JoinTable(name = "employee_project_mapping", joinColumns = @JoinColumn(name = "employee_id", referencedColumnName = "emp_id"), inverseJoinColumns = @JoinColumn(name = "project_id", referencedColumnName = "pjt_id"))
@JsonManagedReference
@ManyToMany(cascade = CascadeType.ALL)
Set<Project> projects = new HashSet<Project>();
......
......
}
@Entity
@Table(name = "projects")
public class Project {
@Id
@GeneratedValue
@Column(name = "pjt_id")
private int projectId;
private String projectName;
private int teamSize;
@ManyToMany(mappedBy = "projects")
@JsonBackReference
private Set<Employee> emp = new HashSet<Employee>();
......
......
}
Find the
below working application.
package com.sample.app.entity;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import com.fasterxml.jackson.annotation.JsonManagedReference;
@Entity
@Table(name = "employees")
public class Employee {
@Id
@GeneratedValue
@Column(name = "emp_id")
private int id;
private String firstName;
private String lastName;
@JoinTable(name = "employee_project_mapping", joinColumns = @JoinColumn(name = "employee_id", referencedColumnName = "emp_id"), inverseJoinColumns = @JoinColumn(name = "project_id", referencedColumnName = "pjt_id"))
@JsonManagedReference
@ManyToMany(cascade = CascadeType.ALL)
Set<Project> projects = new HashSet<Project>();
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Set<Project> getProjects() {
return projects;
}
public void setProjects(Set<Project> projects) {
this.projects = projects;
}
}
Project.java
package com.sample.app.entity;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import com.fasterxml.jackson.annotation.JsonBackReference;
@Entity
@Table(name = "projects")
public class Project {
@Id
@GeneratedValue
@Column(name = "pjt_id")
private int projectId;
private String projectName;
private int teamSize;
@ManyToMany(mappedBy = "projects")
@JsonBackReference
private Set<Employee> emp = new HashSet<Employee>();
public int getProjectId() {
return projectId;
}
public void setProjectId(int projectId) {
this.projectId = projectId;
}
public String getProjectName() {
return projectName;
}
public void setProjectName(String projectName) {
this.projectName = projectName;
}
public Set<Employee> getEmp() {
return emp;
}
public void setEmp(Set<Employee> emp) {
this.emp = emp;
}
public int getTeamSize() {
return teamSize;
}
public void setTeamSize(int teamSize) {
this.teamSize = teamSize;
}
}
EmployeeDto.java
package com.sample.app.dto;
import java.util.List;
public class EmployeeDto {
private String firstName;
private String lastName;
private List<ProjectDto> projects;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public List<ProjectDto> getProjects() {
return projects;
}
public void setProjects(List<ProjectDto> projects) {
this.projects = projects;
}
}
ProjectDto.java
package com.sample.app.dto;
public class ProjectDto {
private String projectName;
private int teamSize;
public String getProjectName() {
return projectName;
}
public void setProjectName(String projectName) {
this.projectName = projectName;
}
public int getTeamSize() {
return teamSize;
}
public void setTeamSize(int teamSize) {
this.teamSize = teamSize;
}
}
EmployeeRepository.java
package com.sample.app.repository;
import org.springframework.data.repository.CrudRepository;
import com.sample.app.entity.Employee;
public interface EmployeeRepository extends CrudRepository<Employee, Integer> {
}
EmployeeService.java
package com.sample.app.service;
import com.sample.app.dto.EmployeeDto;
import com.sample.app.entity.Employee;
public interface EmployeeService {
Employee save(EmployeeDto emp);
Employee getById(int id);
}
EmployeeServiceImpl.java
package com.sample.app.service.impl;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import javax.transaction.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.sample.app.dto.EmployeeDto;
import com.sample.app.dto.ProjectDto;
import com.sample.app.entity.Employee;
import com.sample.app.entity.Project;
import com.sample.app.repository.EmployeeRepository;
import com.sample.app.service.EmployeeService;
@Service
public class EmployeeServiceImpl implements EmployeeService {
@Autowired
private EmployeeRepository empRepo;
@Override
@Transactional
public Employee save(EmployeeDto empDto) {
String firstName = empDto.getFirstName();
String lastName = empDto.getLastName();
Employee emp = new Employee();
emp.setFirstName(firstName);
emp.setLastName(lastName);
List<Project> projectToBeSaved = new ArrayList<>();
for (ProjectDto dto : empDto.getProjects()) {
Project tempPjt = new Project();
tempPjt.setProjectName(dto.getProjectName());
tempPjt.setTeamSize(dto.getTeamSize());
projectToBeSaved.add(tempPjt);
}
emp.setProjects(new HashSet<>(projectToBeSaved));
return empRepo.save(emp);
}
@Override
public Employee getById(int id) {
return empRepo.findById(id).get();
}
}
EmployeeController.java
package com.sample.app.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.sample.app.dto.EmployeeDto;
import com.sample.app.entity.Employee;
import com.sample.app.service.EmployeeService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@RestController
@Api(tags = "Employee Controller", value = "This section contains all Employee Speicifc Operations")
public class EmployeeController {
@Autowired
private EmployeeService empService;
@ApiOperation(value = "Create new Employee", notes = "Create new Employee")
@PostMapping(value = "/employees", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Employee> saveEmployee(@RequestBody EmployeeDto empDto) {
Employee persistedEmp = empService.save(empDto);
return new ResponseEntity<>(persistedEmp, HttpStatus.CREATED);
}
@ApiOperation(value = "Get Employee", notes = "Get employee by id")
@GetMapping(value = "/employees/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Employee> getEmployees(@PathVariable final Integer id) {
Employee persistedEmp = empService.getById(id);
return new ResponseEntity<>(persistedEmp, HttpStatus.CREATED);
}
}
SwaggerConfig.java
package com.sample.app.config;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Component
@EnableAutoConfiguration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket userApi() {
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select().paths(PathSelectors.any())
.apis(RequestHandlerSelectors.basePackage("com.sample.app.controller")).build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder().title("Query builder").description("Query builder using spring specification")
.version("2.0").build();
}
}
App.java
package com.sample.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class App {
public static void main(String args[]) {
SpringApplication.run(App.class, args);
}
}
pom.xml
<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>com.sample.app</groupId>
<artifactId>manyToMany</artifactId>
<version>1</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-jpa -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.h2database/h2 -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-envers -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-envers</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
</dependencies>
</project>
Create
application.properties file under src/main/resources folder.
logging.level.root=WARN logging.level.org.hibernate=ERROR ## H2 specific properties spring.h2.console.enabled=true spring.h2.console.path=/h2 spring.datasource.url=jdbc:h2:file:~/db/myOrg.db;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1; spring.datasource.username=krishna spring.datasource.password=password123 spring.datasource.driverClassName=org.h2.Driver ## JPA specific properties # Creates the schema, destroying previous data. spring.jpa.hibernate.ddl-auto=create spring.jpa.database-platform=org.hibernate.dialect.H2Dialect spring.jpa.show-sql=true #spring.jpa.properties.hibernate.format_sql=true ## Database connection pooling properties # Number of ms to wait before throwing an exception if no connection is available. spring.datasource.max-wait=10000 # Maximum number of active connections that can be allocated from this pool at the same time. spring.datasource.tomcat.max-active=10 spring.datasource.tomcat.max-idle=5 spring.datasource.tomcat.min-idle=3 spring.jackson.serialization.FAIL_ON_EMPTY_BEANS=false
Total Project structure looks like below.
Run App.java.
Open the
url ‘http://localhost:8080/swagger-ui.html’ to see the swagger User Interface.
Open the
url ‘http://localhost:8080/h2/login.do’, to see H2 database console.
You can
download complete working application from this link.
No comments:
Post a Comment