One to One mapping in JPA with Spring Boot
In this guide, we will discuss one to one mapping in JPA with Spring Boot. Spring Boot uses the Hibernate to manage the database level operation and it implements Java Persistence API (JPA) specifications. Hibernate maps the tables into the database to the entity classes of the application.
What we’ll build
In this example, we will define the one-to-one relationship between the two entities using Spring Data JPA. To do that JPA gives:
@OneToOne
– Specifies a single-valued association to another entity that has a one-to-one multiplicity.@JoinColumn
– Specifies a column for joining an entity association or element collection.
The one-to-one relationship between EMPLOYEE and EMPLOYEE_DETAILS tables are as following:
- EMPLOYEE table store only basic information an employee like id, first name, last name, email.
- And EMPLOYEE_DETAILS table store the rest of other information of an employee like job title, gender, salary, etc.
Technology Used
Find the list of all technologies used in this application.
- Spring Tool Suite 4
- JDK 8
- Spring Boot 2.1.6.RELEASE
- Spring Data 2.1.9.RELEASE
- MySQL Database
- Maven 3
Dependency Required
Dependencies used in this example. Add them to pom.xml.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
Steps to be follow
These are the steps we need to follow to get an error-free application.
1. Make sure the above-mentioned dependencies are in the project classpath.
2. Database connection strings have been defined in the application.properties file.
spring.datasource.url=jdbc:mysql://localhost:3306/demo
spring.datasource.username=root
#and other credentials
3. Employee
entity class mappedBy="employee"
field of EmployeeDetails
entity class and annotated by @OneToOne
annotation.
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "employee")
private EmployeeDetails employeeDetail;
4. Similarly, EmployeeDetails
entity class declared an employee field of type Employee
and joined by employee_id using annotation @JoinColumn
& @OneToOne
.
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "employee_id", nullable = false, unique = true)
private Employee employee;
5. Create the Employee
and EmployeeDetails
object of calling its parameterized constructor.
Employee employee = new Employee("Sandeep", "Jaiswal", "[email protected]");
EmployeeDetails employeeDetail = new EmployeeDetails("Database Architect", "Information Technology", "MALE", 92000L, "London,UK");
6. Set child reference (employeeDetail) in the parent entity (employee).
employee.setEmployeeDetail(employeeDetail);
7. Set parent reference(employee) in child entity(employeeDetail).
employeeDetail.setEmployee(employee);
8. Finally, save in the database.
employeeRepository.save(employee);
application.properties
Setup the database connection strings in application.properties.
# MySQL database connection strings
spring.datasource.url=jdbc:mysql://localhost:3306/demo
spring.datasource.username=root
spring.datasource.password=root
# JPA property settings
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL55Dialect
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.show_sql=true
Entity
Create the Employee
and EmployeeDetails
entity class for table EMPLOYEE and EMPLOYEE_DETAILS respectively which will be mapped by one-to-one relationship.
package org.websparrow.entity;
import java.io.Serializable;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;
@Entity
@Table(name = "EMPLOYEE")
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstName;
private String lastName;
@Column(unique = true)
private String email;
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "employee")
private EmployeeDetails employeeDetail;
// TODO: Generate Getters and Setters...
public Employee() { }
public Employee(String firstName, String lastName, String email) {
super();
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
}
package org.websparrow.entity;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;
@Entity
@Table(name = "EMPLOYEE_DETAILS")
public class EmployeeDetails implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String jobTitle;
private String department;
private String gender;
private Long salary;
private String address;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "employee_id", nullable = false, unique = true)
private Employee employee;
// TODO: Generate Getters and Setters...
public EmployeeDetails() { }
public EmployeeDetails(String jobTitle, String department, String gender, Long salary, String address) {
super();
this.jobTitle = jobTitle;
this.department = department;
this.gender = gender;
this.salary = salary;
this.address = address;
}
}
Repository
Create an EmployeeRepository
& EmployeeDetailsRepository
interface which extends CrudRepository
.
package org.websparrow.repository;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import org.websparrow.entity.Employee;
@Repository
public interface EmployeeRepository extends CrudRepository<Employee, Long> {
}
package org.websparrow.repository;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import org.websparrow.entity.EmployeeDetails;
@Repository
public interface EmployeeDetailsRepository extends CrudRepository<EmployeeDetails, Long> {
}
Test the application
To create the one-to-one relationship between two entities implements the CommandLineRunner
interface to the Spring Boot stater class and overrides it’s run()
method.
package org.websparrow;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.websparrow.entity.Employee;
import org.websparrow.entity.EmployeeDetails;
import org.websparrow.repository.EmployeeRepository;
@SpringBootApplication
public class OneToOneApp implements CommandLineRunner {
@Autowired
private EmployeeRepository employeeRepository;
public static void main(String[] args) {
SpringApplication.run(OneToOneApp.class, args);
}
@Override
public void run(String... args) throws Exception {
// Create a new Employee
Employee employee = new Employee("Sandeep", "Jaiswal", "[email protected]");
// Create Employee Detail
EmployeeDetails employeeDetail = new EmployeeDetails("Database Architect", "Information Technology", "MALE",
92000L, "London,UK");
// Set child reference(employeeDetail) in parent entity(employee)
employee.setEmployeeDetail(employeeDetail);
// Set parent reference(employee) in child entity(employeeDetail)
employeeDetail.setEmployee(employee);
// Save in database
employeeRepository.save(employee);
}
}
Console log
Execute the above class and you will find the below log on your IDE console log.
Hibernate: create table employee (id bigint not null auto_increment, email varchar(255), first_name varchar(255), last_name varchar(255), primary key (id)) engine=InnoDB
Hibernate: create table employee_details (id bigint not null auto_increment, address varchar(255), department varchar(255), gender varchar(255), job_title varchar(255), salary bigint, employee_id bigint not null, primary key (id)) engine=InnoDB
Hibernate: alter table employee drop index UK_fopic1oh5oln2khj8eat6ino0
Hibernate: alter table employee add constraint UK_fopic1oh5oln2khj8eat6ino0 unique (email)
Hibernate: alter table employee_details drop index UK_puftcdm791a7i6e45laapk3tw
Hibernate: alter table employee_details add constraint UK_puftcdm791a7i6e45laapk3tw unique (employee_id)
Hibernate: alter table employee_details add constraint FK7pypt1qfit6hwq53tch4afkuq foreign key (employee_id) references employee (id)
Hibernate: insert into employee (email, first_name, last_name) values (?, ?, ?)
Hibernate: insert into employee_details (address, department, employee_id, gender, job_title, salary) values (?, ?, ?, ?, ?, ?)
Result
Check the database, it associated the table EMPLOYEE‘s column “id” and EMPLOYEE_DETAILS‘s column “employee_id” with one-to-one mapping.
TABLE --> EMPLOYEE
id email first_name last_name
------ ------------------- ---------- -----------
1 [email protected] Sandeep Jaiswal
TABLE --> EMPLOYEE_DETAILS
id address department gender job_title salary employee_id
------ --------- --------------------- ------ ------------------ ------ -------------
1 London,UK Informaton Technology MALE Database Architect 92000 1
Download Source Code: one-to-one-mapping-in-jpa-with-spring-boot.zip