Washington | 22°C (moderate rain)
Implementing One-to-One Mapping in Spring Boot – A Hands‑On Walkthrough

Step‑by‑step guide to link a Student entity with an AadhaarCard using JPA’s @OneToOne annotation

Learn how to model a strict one‑to‑one relationship in Spring Boot with JPA, from project setup to CRUD testing, using a Student‑Aadhaar example.

When you hear "one‑to‑one" in the world of databases, picture a perfect partnership – each record on one side has exactly one counterpart on the other. In a Spring Boot app that usually means sprinkling a couple of JPA annotations and letting Hibernate do the heavy lifting.

In this article we’ll walk through a tiny, yet complete, example: a Student entity that owns a single AadhaarCard. The idea is simple – one student, one Aadhaar – but getting the JPA wiring right can be a bit fiddly if you haven’t done it before.

What you’ll need

  • Java 11 (or newer)
  • Maven
  • MySQL (any recent version)
  • An IDE – IntelliJ, Eclipse, VS Code, whatever you like
  • Spring Initializr (just click a button and download a starter zip)

1. Bootstrap the Spring Boot project

Head over to start.spring.io and pick the following options:

  • Project: Maven
  • Language: Java
  • Spring Boot: 2.5.6 (or any 2.x you’re comfortable with)
  • Packaging: JAR
  • Java: 11
  • Dependencies: Spring Web, Spring Data JPA, MySQL Driver

Hit Generate, unzip the archive, and open it as a Maven project in your IDE. Maven will pull in the dependencies – give it a minute.

2. Wire up the database

We’ll store everything in a local MySQL schema called mapping. Add these lines to src/main/resources/application.properties (replace the password with yours):

spring.datasource.url=jdbc:mysql://localhost:3306/mapping
spring.datasource.username=root
spring.datasource.password=your_password
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

The ddl-auto=update flag tells Hibernate to create or adjust tables automatically – perfect for a demo.

3. Define the entities

Inside a new package com.example.mapping.models create two POJOs. First, the StudentInformation class:

package com.example.mapping.models;

import javax.persistence.*;

@Entity
@Table(name = "student")
public class StudentInformation {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int rollno;

    private String name;

    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "aadhaar_id") // foreign‑key column in student table
    private AadhaarCard aadhaarCard;

    // constructors, getters, setters omitted for brevity
}

Notice the @OneToOne annotation – it says “this student owns exactly one AadhaarCard”. The @JoinColumn tells Hibernate to add a column named aadhaar_id in the student table that points to the primary key of aadhaar_card. By using cascade = CascadeType.ALL we make sure that persisting a student automatically persists its card, and likewise for deletions.

Now the partner entity, AadhaarCard:

package com.example.mapping.models;

import javax.persistence.*;

@Entity
@Table(name = "aadhaar_card")
public class AadhaarCard {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    private String aadhaarNumber;

    // constructors, getters, setters omitted for brevity
}

This side doesn’t need a reference back to StudentInformation unless you want a bi‑directional link – for a simple demo a uni‑directional mapping keeps things tidy.

4. Create the repository layer

Spring Data JPA lets us skip the boilerplate DAO code. In com.example.mapping.repository add two interfaces:

package com.example.mapping.repository;

import com.example.mapping.models.StudentInformation;
import org.springframework.data.jpa.repository.JpaRepository;

public interface StudentRepo extends JpaRepository {}
package com.example.mapping.repository;

import com.example.mapping.models.AadhaarCard;
import org.springframework.data.jpa.repository.JpaRepository;

public interface AadhaarRepo extends JpaRepository {}

That’s it – Spring will generate the implementations at runtime.

5. Seed some data with CommandLineRunner

To see everything in action we’ll insert a couple of rows when the app boots. Open the main class (MappingApplication) and make it implement CommandLineRunner:

package com.example.mapping;

import com.example.mapping.models.AadhaarCard;
import com.example.mapping.models.StudentInformation;
import com.example.mapping.repository.StudentRepo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MappingApplication implements CommandLineRunner {

    @Autowired
    private StudentRepo studentRepo;

    public static void main(String[] args) {
        SpringApplication.run(MappingApplication.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        AadhaarCard card = new AadhaarCard("1234-5678-9012");
        StudentInformation student = new StudentInformation();
        student.setName("Rohit Sharma");
        student.setAadhaarCard(card);
        studentRepo.save(student); // cascades and persists the card as well
    }
}

Start the application (e.g., run mvn spring-boot:run) and watch the console – you’ll see the INSERT statements because we turned show‑sql on earlier.

6. Verify with a quick query

If you connect to MySQL and run SELECT * FROM student; you’ll notice a column aadhaar_id that holds the foreign key. A second query on aadhaar_card will show the matching row. That’s the one‑to‑one relationship in action.

7. A few gotchas

  • Make sure the foreign‑key column is unique if you want the database to enforce the one‑to‑one rule on its own. Add unique = true to @JoinColumn or create a unique constraint manually.
  • If you need a bi‑directional link, add a @OneToOne(mappedBy = "aadhaarCard") field in AadhaarCard and be careful with JSON serialization (use @JsonIgnore to avoid infinite recursion).
  • Lazy loading is the default for @OneToOne, but you can force eager fetching with fetch = FetchType.EAGER – just remember it may affect performance.

That’s pretty much everything you need to get a clean one‑to‑one mapping up and running. From here you can expose REST endpoints, add validation, or even switch to a different database – the JPA mapping stays the same.

Happy coding!

Comments 0
Please login to post a comment. Login
No approved comments yet.

Editorial note: Nishadil may use AI assistance for news drafting and formatting. Readers can report issues from this page, and material corrections are reviewed under our editorial standards.