๐ Mastering Spring Data JPA: Implementing @OneToOne Mapping with User and AadharCard Entities ๐
๐ A Step-by-Step Guide to Efficiently Managing Entity Relationships in Spring Boot Applications ๐
Overview
In this guide, we'll walk through how to establish a @OneToOne relationship between User and AadharCard entities. This mapping type is perfect for scenarios where one entity is closely associated with another, such as a user having a unique identification card. By the end of this tutorial, you'll clearly understand how to implement and utilize @OneToOne mappings in your Spring Boot applications.
JPA One-to-One Mapping
In JPA (Java Persistence API), a one-to-one mapping is used to define a relationship between two entities where each instance of one entity is associated with exactly one instance of the other entity. This is typically represented in the database schema with a foreign key in one table that references the primary key of another table. There are two types of one-to-one mappings: Unidirectional and Bidirectional.
Unidirectional One-to-One Mapping
In unidirectional one-to-one mapping, only one entity knows about the relationship. For example, in our User and AadharCard scenario, if the User knows about AadharCard but AadharCard does not have a reference to the User, it is unidirectional mapping.
Prerequisites
Before we dive in, ensure you have the following installed:
Java Development Kit (JDK) 8 or higher
Spring Boot
Spring Data JPA
MySQL or any other relational database
Step-by-Step Implementation
1. Setting Up the Project
Create a new Spring Boot project using Spring Initializr or your preferred IDE. Add the necessary dependencies for Spring Data JPA and MySQL connector.
Spring Web
Spring Data JPA
MySQL Driver
Lombok
2. Create Entities for Users and AadharCard
User.java
package com.Spring_Data_Jpa.Entity;
import jakarta.persistence.*;
import lombok.Data;
@Entity
@Data
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long ID;
private String name;
private String email;
@OneToOne(cascade = CascadeType.ALL)
private AadharCard aadharCard;
}
AadharCard.java
package com.Spring_Data_Jpa.Entity;
import jakarta.persistence.*;
import lombok.Data;
@Entity
@Data
@Table(name = "aadhar")
public class AadharCard {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private long ID;
private long number;
}
3. Repository interface for managing entities
UserRepository
package com.Spring_Data_Jpa.Repository;
import com.Spring_Data_Jpa.Entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRepository extends JpaRepository<User, Long> { }
AadharCardRepository
package com.Spring_Data_Jpa.Repository;
import com.Spring_Data_Jpa.Entity.AadharCard;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface AadharCardRepository extends JpaRepository<AadharCard, Long> { }
4. Controller class for handling requests related to User Entities
UserController
package com.Spring_Data_Jpa.Controller;
import com.Spring_Data_Jpa.Entity.User;
import com.Spring_Data_Jpa.Repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
@Autowired
UserRepository userRepository;
@PostMapping("/addUser")
public String addUser(@RequestBody User user) {
userRepository.save(user);
return "User and AadharCard saved successfully!";
}
}
5. Database Configuration
spring.application.name=Spring-Data-JPA
#Database MySQL
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3307/mapping_db
spring.datasource.username=root
spring.datasource.password=root1234
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
6. SQL Scripts
use user_db;
CREATE TABLE aadhar (
id bigint NOT NULL AUTO_INCREMENT,
number bigint NOT NULL unique,
PRIMARY KEY (id)
);
CREATE TABLE user (
ID bigint NOT NULL AUTO_INCREMENT,
name varchar(100) DEFAULT NULL,
email varchar(100) DEFAULT NULL,
aadhar_card_id bigint DEFAULT NULL,
PRIMARY KEY (ID),
UNIQUE KEY (aadhar_card_id),
CONSTRAINT FOREIGN KEY (aadhar_card_id) REFERENCES aadhar (id)
);
Testing the @OneToOne Mapping with Postman
Add User: POST /addUser
{
"name" : "K Jordan",
"email" : "jordank@gmail.com",
"aadharCard": {
"number": 516273819025
}
}
In the unidirectional mapping, each User
has a field called aadhar_card_id
, which acts as a foreign key referencing the AadharCard
entity. This setup allows us to associate each User
with exactly one AadharCard
, and the relationship is established by storing the AadharCard
ID in the User
table.
Bidirectional One-to-One Mapping
In bidirectional one-to-one mapping, both entities are aware of the relationship. Continuing with our example, if the User has a reference to AadharCard and AadharCard also has a reference to the User, it is bidirectional mapping.
You need to add a@OneToOne
annotation in theAadharCard
entity to reference theUser
entity. Additionally, you need to update theUser
the entity to properly link to theAadharCard
entity. Here's how you can do it:
AadharCard
package com.Spring_Data_Jpa.Entity;
import jakarta.persistence.*;
import lombok.Data;
@Entity
@Data
@Table(name = "aadhar")
public class AadharCard {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private long ID;
@Column(name = "number")
private long number;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "user_id")
private User user;
}
UserController
In the controller, ensure that you set both sides of the relationship before saving:
package com.Spring_Data_Jpa.Controller;
import com.Spring_Data_Jpa.Entity.AadharCard;
import com.Spring_Data_Jpa.Entity.User;
import com.Spring_Data_Jpa.Repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
@Autowired
UserRepository userRepository;
@PostMapping("/addUser")
public String addUser(@RequestBody User user, AadharCard aadharCard) {
// Ensure both sides of the relationship are properly set
if (user.getAadharCard() != null) {
aadharCard = user.getAadharCard();
aadharCard.setUser(user); // Set the user in the AadharCard
}
userRepository.save(user);
return "User and AadharCard saved successfully!";
}
}
In the bidirectional mapping, each User
the entity has a field called aadharCard
that holds a reference to its associated AadharCard
entity, and each AadharCard
the entity has a field called user
that holds a reference back to its associated User
entity. This bidirectional relationship enables us to navigate from a User
to its AadharCard
and vice versa, providing more flexibility in managing and accessing the relationship between the two entities.
Conclusion:
In our setup, we've implemented both unidirectional and bidirectional one-to-one mappings between the User
and AadharCard
entities.
These mappings provide us with flexibility in managing the relationship between users and AadharCards. The unidirectional mapping simplifies the database structure by storing the AadharCard ID in the User table, while the bidirectional mapping allows for easy navigation between User and AadharCard entities, enhancing the readability and maintainability of our code.
GitHub Access:
You can access the code on GitHub here. Feel free to fork the repository and try it out yourself.