Introduction
One-to-One mapping in Hibernate represents a relationship where each record in one table corresponds to exactly one record in another table. This is commonly used when entities have exclusive relationships, such as User and Address.
In this tutorial, we will:
- Create a User entity with a one-to-one relationship to an Address entity.
- Generate database tables in Oracle Express Edition.
- Perform CRUD operations.
Project Setup
Ensure you have the following dependencies in your pom.xml
:
<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>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<scope>runtime</scope>
</dependency>
<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>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<scope>runtime</scope>
</dependency>
<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>com.oracle.database.jdbc</groupId> <artifactId>ojdbc8</artifactId> <scope>runtime</scope> </dependency>
Database Configuration
Configure the application.properties file:
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:xe
spring.datasource.username=system
spring.datasource.password=admin
spring.datasource.driver-class-name=oracle.jdbc.OracleDriver
# JPA Properties
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.database-platform=org.hibernate.dialect.OracleDialect
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:xe
spring.datasource.username=system
spring.datasource.password=admin
spring.datasource.driver-class-name=oracle.jdbc.OracleDriver
# JPA Properties
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.database-platform=org.hibernate.dialect.OracleDialect
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:xe spring.datasource.username=system spring.datasource.password=admin spring.datasource.driver-class-name=oracle.jdbc.OracleDriver # JPA Properties spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql=true spring.jpa.database-platform=org.hibernate.dialect.OracleDialect
Creating entities
User Entity
package com.learnitweb.hibernatedemo.entity;
import jakarta.persistence.*;
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "address_id", referencedColumnName = "id")
private Address address;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
address.setUser(this);
}
}
package com.learnitweb.hibernatedemo.entity;
import jakarta.persistence.*;
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "address_id", referencedColumnName = "id")
private Address address;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
address.setUser(this);
}
}
package com.learnitweb.hibernatedemo.entity; import jakarta.persistence.*; @Entity @Table(name = "users") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; @OneToOne(cascade = CascadeType.ALL) @JoinColumn(name = "address_id", referencedColumnName = "id") private Address address; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; address.setUser(this); } }
Address Entity
package com.learnitweb.hibernatedemo.entity;
import jakarta.persistence.*;
@Entity
@Table(name = "address")
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String street;
private String city;
private String country;
@OneToOne(mappedBy = "address", cascade = CascadeType.ALL)
private User user;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
package com.learnitweb.hibernatedemo.entity;
import jakarta.persistence.*;
@Entity
@Table(name = "address")
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String street;
private String city;
private String country;
@OneToOne(mappedBy = "address", cascade = CascadeType.ALL)
private User user;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
package com.learnitweb.hibernatedemo.entity; import jakarta.persistence.*; @Entity @Table(name = "address") public class Address { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String street; private String city; private String country; @OneToOne(mappedBy = "address", cascade = CascadeType.ALL) private User user; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getStreet() { return street; } public void setStreet(String street) { this.street = street; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } }
SQL Statements to Create Tables
For Oracle Express Edition, use the following SQL statements:
CREATE TABLE address (
id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
street VARCHAR2(255),
city VARCHAR2(255),
country VARCHAR2(255)
);
CREATE TABLE users (
id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
name VARCHAR2(255),
address_id NUMBER UNIQUE,
CONSTRAINT fk_address FOREIGN KEY (address_id) REFERENCES address(id)
);
CREATE TABLE address (
id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
street VARCHAR2(255),
city VARCHAR2(255),
country VARCHAR2(255)
);
CREATE TABLE users (
id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
name VARCHAR2(255),
address_id NUMBER UNIQUE,
CONSTRAINT fk_address FOREIGN KEY (address_id) REFERENCES address(id)
);
CREATE TABLE address ( id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, street VARCHAR2(255), city VARCHAR2(255), country VARCHAR2(255) ); CREATE TABLE users ( id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY, name VARCHAR2(255), address_id NUMBER UNIQUE, CONSTRAINT fk_address FOREIGN KEY (address_id) REFERENCES address(id) );
Creating Repositories
User Repository
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {}
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {}
import org.springframework.data.jpa.repository.JpaRepository; public interface UserRepository extends JpaRepository<User, Long> {}
Address Repository
import org.springframework.data.jpa.repository.JpaRepository;
public interface AddressRepository extends JpaRepository<Address, Long> {}
import org.springframework.data.jpa.repository.JpaRepository;
public interface AddressRepository extends JpaRepository<Address, Long> {}
import org.springframework.data.jpa.repository.JpaRepository; public interface AddressRepository extends JpaRepository<Address, Long> {}
Service Layer
package com.learnitweb.hibernatedemo.service;
import com.learnitweb.hibernatedemo.entity.Address;
import com.learnitweb.hibernatedemo.entity.User;
import com.learnitweb.hibernatedemo.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Optional;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public User createUser(User user) {
return userRepository.save(user);
}
public Optional<User> getUserById(Long id) {
return userRepository.findById(id);
}
public User updateUser(Long id, User userDetails) {
return userRepository.findById(id).map(user -> {
user.setName(userDetails.getName());
user.setAddress(userDetails.getAddress());
return userRepository.save(user);
}).orElseThrow(() -> new RuntimeException("User not found"));
}
public void deleteUser(Long id) {
userRepository.deleteById(id);
}
public User patchUser(Long id, User userDetails) {
return userRepository.findById(id).map(user -> {
user.setName(userDetails.getName());
Address existingAddress = user.getAddress();
existingAddress.setCountry(userDetails.getAddress().getCountry());
existingAddress.setCity(userDetails.getAddress().getCity());
existingAddress.setStreet(userDetails.getAddress().getCity());
user.setAddress(existingAddress);
return userRepository.save(user);
}).orElseThrow(() -> new RuntimeException("User not found"));
}
}
package com.learnitweb.hibernatedemo.service;
import com.learnitweb.hibernatedemo.entity.Address;
import com.learnitweb.hibernatedemo.entity.User;
import com.learnitweb.hibernatedemo.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Optional;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public User createUser(User user) {
return userRepository.save(user);
}
public Optional<User> getUserById(Long id) {
return userRepository.findById(id);
}
public User updateUser(Long id, User userDetails) {
return userRepository.findById(id).map(user -> {
user.setName(userDetails.getName());
user.setAddress(userDetails.getAddress());
return userRepository.save(user);
}).orElseThrow(() -> new RuntimeException("User not found"));
}
public void deleteUser(Long id) {
userRepository.deleteById(id);
}
public User patchUser(Long id, User userDetails) {
return userRepository.findById(id).map(user -> {
user.setName(userDetails.getName());
Address existingAddress = user.getAddress();
existingAddress.setCountry(userDetails.getAddress().getCountry());
existingAddress.setCity(userDetails.getAddress().getCity());
existingAddress.setStreet(userDetails.getAddress().getCity());
user.setAddress(existingAddress);
return userRepository.save(user);
}).orElseThrow(() -> new RuntimeException("User not found"));
}
}
package com.learnitweb.hibernatedemo.service; import com.learnitweb.hibernatedemo.entity.Address; import com.learnitweb.hibernatedemo.entity.User; import com.learnitweb.hibernatedemo.repository.UserRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.Optional; @Service public class UserService { @Autowired private UserRepository userRepository; public User createUser(User user) { return userRepository.save(user); } public Optional<User> getUserById(Long id) { return userRepository.findById(id); } public User updateUser(Long id, User userDetails) { return userRepository.findById(id).map(user -> { user.setName(userDetails.getName()); user.setAddress(userDetails.getAddress()); return userRepository.save(user); }).orElseThrow(() -> new RuntimeException("User not found")); } public void deleteUser(Long id) { userRepository.deleteById(id); } public User patchUser(Long id, User userDetails) { return userRepository.findById(id).map(user -> { user.setName(userDetails.getName()); Address existingAddress = user.getAddress(); existingAddress.setCountry(userDetails.getAddress().getCountry()); existingAddress.setCity(userDetails.getAddress().getCity()); existingAddress.setStreet(userDetails.getAddress().getCity()); user.setAddress(existingAddress); return userRepository.save(user); }).orElseThrow(() -> new RuntimeException("User not found")); } }
Controller
package com.learnitweb.hibernatedemo.controller;
import com.learnitweb.hibernatedemo.entity.User;
import com.learnitweb.hibernatedemo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.Optional;
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserService userService;
@PostMapping
public ResponseEntity<User> createUser(@RequestBody User user) {
return ResponseEntity.ok(userService.createUser(user));
}
@GetMapping("/{id}")
public ResponseEntity<User> getUserById(@PathVariable Long id) {
Optional<User> user = userService.getUserById(id);
return user.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound().build());
}
@PatchMapping("/{id}")
public ResponseEntity<User> updateUser(@PathVariable Long id, @RequestBody User userDetails) {
return ResponseEntity.ok(userService.patchUser(id, userDetails));
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
return ResponseEntity.noContent().build();
}
}
package com.learnitweb.hibernatedemo.controller;
import com.learnitweb.hibernatedemo.entity.User;
import com.learnitweb.hibernatedemo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.Optional;
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserService userService;
@PostMapping
public ResponseEntity<User> createUser(@RequestBody User user) {
return ResponseEntity.ok(userService.createUser(user));
}
@GetMapping("/{id}")
public ResponseEntity<User> getUserById(@PathVariable Long id) {
Optional<User> user = userService.getUserById(id);
return user.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound().build());
}
@PatchMapping("/{id}")
public ResponseEntity<User> updateUser(@PathVariable Long id, @RequestBody User userDetails) {
return ResponseEntity.ok(userService.patchUser(id, userDetails));
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
return ResponseEntity.noContent().build();
}
}
package com.learnitweb.hibernatedemo.controller; import com.learnitweb.hibernatedemo.entity.User; import com.learnitweb.hibernatedemo.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.Optional; @RestController @RequestMapping("/users") public class UserController { @Autowired private UserService userService; @PostMapping public ResponseEntity<User> createUser(@RequestBody User user) { return ResponseEntity.ok(userService.createUser(user)); } @GetMapping("/{id}") public ResponseEntity<User> getUserById(@PathVariable Long id) { Optional<User> user = userService.getUserById(id); return user.map(ResponseEntity::ok).orElseGet(() -> ResponseEntity.notFound().build()); } @PatchMapping("/{id}") public ResponseEntity<User> updateUser(@PathVariable Long id, @RequestBody User userDetails) { return ResponseEntity.ok(userService.patchUser(id, userDetails)); } @DeleteMapping("/{id}") public ResponseEntity<Void> deleteUser(@PathVariable Long id) { userService.deleteUser(id); return ResponseEntity.noContent().build(); } }
Explanation of Annotations
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "address_id", referencedColumnName = "id")
private Address address;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "address_id", referencedColumnName = "id")
private Address address;
@OneToOne(cascade = CascadeType.ALL) @JoinColumn(name = "address_id", referencedColumnName = "id") private Address address;
- Specifies the foreign key column in the owning entity.
name
: Defines the foreign key column in the current table.referencedColumnName
: Defines which column in the referenced table the foreign key points to.- In
User
,@JoinColumn(name = "address_id", referencedColumnName = "id")
means thataddress_id
in theusers
table referencesid
in theaddress
table.
@OneToOne(mappedBy = "address", cascade = CascadeType.ALL)
private User user;
@OneToOne(mappedBy = "address", cascade = CascadeType.ALL)
private User user;
@OneToOne(mappedBy = "address", cascade = CascadeType.ALL) private User user;
- Used in the non-owning entity to establish the bidirectional relationship.
mappedBy
: Specifies the field in the owning entity that maps this relationship.cascade = CascadeType.ALL
: Ensures that any operation (persist, merge, remove) cascades to the related entity.- In
Address
,@OneToOne(mappedBy = "address", cascade = CascadeType.ALL)
links it back to theUser
entity, indicating thatUser
owns the relationship.