We design data base tables relationships by connecting them using foreign key reference columns. Most of the relationship between entities boils down into a entity class having one or many entity(entities) of another type. With different combinations we can have one-to-one, one-to-many, many-to-one and many-to-many relationships.
In the previous article, we learned how to perform RESTful CRUD operation using spring data JPA. In this article, we are going to learn about JPA one-to-one entity mapping.
We will implement JPA one to one by mapping an Employee object and Address object. In real world scenario, an employee may have different types of addresses(Ex: permanent address, current address, etc).
In our example we are assuming that an employee will have only one address mapped to every him/her, which is a one to one JPA mapping scenario.
We will be creating RESTful JPA CRUD application with one to one JPA mapping in this article.
Following are the version details
- Java version 1.8
- Spring boot version : 2.1.5-RELEASE
- IDE: STS Version 4
- Database : PostgreSQL 9.5 Java version 1.8
- Lombok : For avoiding boiler plate codes.
- Postman : For testing REST end points.
Steps to create spring boot JPA one to one mapping
- Create a spring boot application with required dependencies.
- Add database related configurations.
- Create Entity classes, mapping and repository interface and database tables.
- Create a service layer and a Rest(Representational State Transfer) controller layer.
Create a Spring boot application with required dependencies
Since we are going to create a spring boot RESTful web service application, create a spring boot application with required dependencies. We have to add spring-boot-starter-parent, spring-boot-starter-web, spring-boot-starter-data-jpa dependencies as given in below pom.xml file. These are the core spring boot starter dependencies needed for our application.
We have also added lombok dependency, which is a great open source library, used to reduce boiler plate code. Since we are using PostgreSQL database, we also need to add the dependency to our application.
An optional spring-boot-devtools dependency is also added, which helps in increasing the developers productivity.
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.asb.example</groupId>
<artifactId>spring-boot-jpa-one-to-one</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-jpa-one-to-one</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<!-- https://mvnrepository.com/artifact/org.postgresql/postgresql -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Add database related configurations
Add the required database configuration properties to spring boot applications application.properties (under directory : /src/main/resources)file.
First 3 properties are database connection properties having connection url, database username and password details.
spring.jpa.hibernate.naming.physical-strategy : By setting this property value, we are stating that the database table and column values defined should strictly follow hibernate naming strategy conventions. Default spring’s naming convention replaces camel case entity names with underscore(“_”). More information is given here.
application.properties
spring.datasource.url=jdbc:postgresql://localhost/postgres
spring.datasource.username=postgres
spring.datasource.password=asbnotebook
#Enable physcical naming strategy.
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true
spring.jpa.hibernate.ddl-auto=none
spring.jpa.show-sql=true
Following is the Spring boot application class, which is the entry point of spring boot application.
SpringBootJpaOneToOneApplication.java
package com.asb.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBootJpaOneToOneApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootJpaOneToOneApplication.class, args);
}
}
Create Entity classes, mapping and repository interface and database tables
Create an Entity class with name Employee.java. Add the required fields as given below.
Notice the field address, which is annotated with @OneToOne JPA annotation. This annotation indicates the one to one relation ship between entities. In our example, an employee can have one address associated with him.
@JoinColumn annotation is used on the owning side of the entity. In our example, employeedetails table is having foreign key reference to address table’s Id column, so annotation is used in Employee entity class with foreign key reference column.
Also notice that the cascade property value is set to CascadeType.ALL, which indicates that all entity related operations(MERGE, DELETE, DETACH, REFRESH, REMOVE) are cascaded between related entities.
Employee.java
package com.asb.example.model;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Entity
@AllArgsConstructor
@Getter
@Setter
@NoArgsConstructor
@Table(name="employeedetails")
public class Employee {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="Id")
private Long id;
@Column(name="EmployeeName")
private String employeeName;
@Column(name="EmployeeCode")
private String employeeCode;
@Column(name="Designation")
private String designation;
@OneToOne(cascade=CascadeType.ALL)
@JoinColumn(name="addressid")
private Address address;
}
Create another entity class named Address.java as given below. This entity class contains address details related to the Employee entity.
We are using database sequence to generate Id, by using @SequenceGenerator annotation. We will also going to create a sequence with name address_sequence in later steps.
Address.java
package com.asb.example.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import lombok.Getter;
import lombok.Setter;
@Entity
@Table(name="address")
@Getter
@Setter
public class Address {
@Id
@Column(name="id")
@SequenceGenerator(initialValue=1, name="address_seq", sequenceName="address_sequence")
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="address_seq")
private int id;
@Column(name="doornumber")
private String doorNumber;
@Column(name="street")
private String street;
@Column(name="city")
private String city;
}
Note that we have implemented unidirectional entity mapping in our example. i.e, only Employee entity is having mapping details. With bidirectional mapping, inverse side(Address Entity) will also have mapping details with mappedBy property as shown below.
@OneToOne(mappedBy="address")
private List<Employee> empList;
Here address is the instance variable name created in Employee Entity class. Adding bidirectional mapping gives two way data access from both entity sides.
Create a EmployeeRepository.java interface and extend JpaRepository to inherit the out of the box JPA basic operation support.
EmployeeRepository.java
package com.asb.example.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.asb.example.model.Employee;
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
}
Run the below given SQL scripts on the database. Here, first two SQL scripts are to create database tables employeedetails and address respectively.
We are also creating a database sequence named address_sequence, which is used for id column of address entity in earlier part.
SQL scripts :
CREATE TABLE public.employeedetails
(
id bigint NOT NULL,
designation character varying(255),
employeecode character varying(255),
employeename character varying(255),
addressid bigint,
CONSTRAINT employee_pk PRIMARY KEY (id),
FOREIGN KEY (addressid) REFERENCES address(id)
)
CREATE TABLE public.address
(
id bigint NOT NULL PRIMARY KEY,
doornumber varchar(3),
street varchar(250),
city varchar(50)
)
CREATE SEQUENCE address_sequence
START WITH 1
INCREMENT BY 1
Create a service layer and a Rest(Representational State Transfer) controller layer
Create an interface with name EmployeeService.java and add required methods to it as shown below.
EmployeeService.java
package com.asb.example.service;
import java.util.List;
import com.asb.example.model.Employee;
public interface EmployeeService {
public Employee createEmployee(Employee emp);
public Employee updateEmployee(Employee emp);
public Employee getEmployee(Long empId);
public void deleteEmployee(Long empId);
public List<Employee> getAllEmployee();
}
Create an implementation class with name EmployeeServiceImpl.java and provide required implementation for the defined methods as given below.
EmployeeServiceImpl.java
package com.asb.example.service;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.asb.example.model.Employee;
import com.asb.example.repository.EmployeeRepository;
@Service
public class EmployeeServiceImpl implements EmployeeService {
@Autowired
private EmployeeRepository employeeRepository;
@Override
public Employee createEmployee(Employee emp) {
return employeeRepository.save(emp);
}
@Override
public Employee updateEmployee(Employee emp) {
return employeeRepository.save(emp);
}
@Override
public Employee getEmployee(Long empId) {
Optional<Employee> optionalEmp = employeeRepository.findById(empId);
if (optionalEmp.isPresent()) {
return optionalEmp.get();
}
return null;
}
@Override
public void deleteEmployee(Long empId) {
employeeRepository.deleteById(empId);
}
@Override
public List<Employee> getAllEmployee() {
return employeeRepository.findAll();
}
}
Create a REST controller and add required methods to support CRUD operations. This controller class will have RESTful service end points for create, update, delete, get employee by Id and get all available employee details operations.
EmployeeController.java
package com.asb.example.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
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.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.asb.example.model.Employee;
import com.asb.example.service.EmployeeService;
@RestController
public class EmployeeController {
@Autowired
private EmployeeService employeeService;
@PostMapping(consumes = "application/json", produces = "application/json", path = "/employee")
public ResponseEntity<Employee> createEmployee(@RequestBody Employee emp) {
return new ResponseEntity<>(employeeService.createEmployee(emp), HttpStatus.CREATED);
}
@PutMapping(consumes = "application/json", produces = "application/json", path = "/employee")
public ResponseEntity<Employee> updateEmployee(@RequestBody Employee emp) {
return new ResponseEntity<>(employeeService.updateEmployee(emp), HttpStatus.CREATED);
}
@DeleteMapping(produces = "application/json", consumes = "text/plain", path = "/employee/{empId}")
public ResponseEntity<String> deleteEmployee(@PathVariable(value = "empId") Long empId) {
employeeService.deleteEmployee(empId);
return new ResponseEntity<>("Employee with EmployeeId : " + empId + " deleted successfully", HttpStatus.OK);
}
@GetMapping(path = "/employee/{empId}", produces = "application/json")
public ResponseEntity<Employee> getEmployee(@PathVariable(value = "empId") Long empId) {
return new ResponseEntity<>(employeeService.getEmployee(empId), HttpStatus.OK);
}
@GetMapping(path = "/employees", produces = "application/json")
public ResponseEntity<List<Employee>> getAllEmployees() {
return new ResponseEntity<>(employeeService.getAllEmployee(), HttpStatus.OK);
}
}
Output
Our spring boot JPA one to one mapping example application is ready now.!!
Run the application and use the Postman tool to test the RESTful service end points as explained below.
Create Employee :
Below image shows creation of employee entity. We are passing address details of employee in the input request to the URL : http://localhost:8080/employee/.
Make sure that required request header values are set in postman header tab(ContentType : application/json and Accepts : application/json).

Below image displays the SQL scripts generated by the JPA internally to persist the entity into database.

Update Employee:
To update employee details, we use same URL (same as create example) with HTTP method PUT.
Notice the Id details, which should be sent on request body. header details remains same, as we are sending and receiving JSON values.

Below image shows SQL script generated to update the entity details.

Get Employee:
We can get the employee details by passing Employee Id with URL : http://localhost:8080/employee/{id}. In our example below, employee id is 11.
This is a HTTP GET operation and ContentType header can be ignored as there is no request input content in request body.

Get All Employee details :
This end point returns all available employee entities as shown below.

Delete Employee:
To delete employee by Id, we use the URL : http//:localhost:8080/employee/{id} and HTTP request method DELETE as shown below.

Below image shows SQL delete script generated by the application.

database value:
Following images shows values stored in the PostgreSQL database. We can see both Employee and Address details are persisted in database as expected. well done !!! 🙂 🙂


Complete Source code is available here.
In this article, we learned about spring boot JPA one to one mapping.
can i have the code please
LikeLike
Github link is already given in the post.
LikeLike