In real-world applications, data is often related. For example:
- A user may have one profile
- A customer can place many orders
- A student can enroll in many courses
Entity Relationships in Spring Data JPA (with Hibernate) allows you to map these relationships easily using annotations.
This guide will explain:
- What are entity relationships?
@OneToOne
mapping@OneToMany
and@ManyToOne
mapping@ManyToMany
mapping- Examples for each with code

๐ What Are Entity Relationships in Spring Data JPA?
In databases, relationships describe how tables are connected:
Type | Description | Example |
---|---|---|
One-to-One | One record relates to one other record | One user has one profile |
One-to-Many | One record relates to many records | One customer has many orders |
Many-to-Many | Many records relate to many records | A student enrolls in many courses and a course has many students |
1๏ธโฃ OneToOne Mapping
๐ก Example: A User
has one Profile
๐ง User Entity
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
@Entity public class User { @Id @GeneratedValue private Long id; private String name; @OneToOne(mappedBy = "user", cascade = CascadeType.ALL) private Profile profile; // getters and setters } |
๐ง Profile Entity
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
@Entity public class Profile { @Id @GeneratedValue private Long id; private String bio; @OneToOne @JoinColumn(name = "user_id") private User user; // getters and setters } |
โ Notes:
mappedBy
: used on the non-owning side@JoinColumn
: used on the owning side to define the foreign key
2๏ธโฃ OneToMany and ManyToOne Mapping
๐ก Example: A Customer
has many Orders
๐ง Customer Entity
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
@Entity public class Customer { @Id @GeneratedValue private Long id; private String name; @OneToMany(mappedBy = "customer", cascade = CascadeType.ALL) private List<Order> orders = new ArrayList<>(); // getters and setters } |
๐ง Order Entity
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
@Entity public class Order { @Id @GeneratedValue private Long id; private String product; @ManyToOne @JoinColumn(name = "customer_id") private Customer customer; // getters and setters } |
โ Notes:
@OneToMany
is typically placed on the parent side@ManyToOne
defines the foreign key in the child
3๏ธโฃ ManyToMany Mapping
๐ก Example: A Student
can enroll in many Courses
and a Course
can have many Students
๐ง Student Entity
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
@Entity public class Student { @Id @GeneratedValue private Long id; private String name; @ManyToMany @JoinTable( name = "student_course", joinColumns = @JoinColumn(name = "student_id"), inverseJoinColumns = @JoinColumn(name = "course_id") ) private List<Course> courses = new ArrayList<>(); // getters and setters } |
๐ง Course Entity
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
@Entity public class Course { @Id @GeneratedValue private Long id; private String title; @ManyToMany(mappedBy = "courses") private List<Student> students = new ArrayList<>(); // getters and setters } |
โ Notes:
@JoinTable
creates a third (join) table to hold many-to-many relationshipsmappedBy
is used on the inverse side
๐ How to Test These Relationships
You can create sample data in a CommandLineRunner or using a controller:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
@Bean CommandLineRunner run(StudentRepository studentRepo, CourseRepository courseRepo) { return args -> { Course java = new Course("Java Basics"); Course spring = new Course("Spring Boot"); Student student = new Student("Alice"); student.getCourses().add(java); student.getCourses().add(spring); java.getStudents().add(student); spring.getStudents().add(student); studentRepo.save(student); }; } |
๐งผ Cascading and Fetch Types
Cascade Types:
CascadeType.PERSIST
: Propagates saveCascadeType.REMOVE
: Deletes child when parent is deletedCascadeType.ALL
: All operations are cascaded
Fetch Types:
FetchType.LAZY
: Loads only when neededFetchType.EAGER
: Loads immediately
๐ก Prefer LAZY
for large data sets to avoid performance issues.
โ Summary
Annotation | Description |
---|---|
@OneToOne | One-to-one mapping |
@OneToMany | One-to-many mapping |
@ManyToOne | Many-to-one mapping |
@ManyToMany | Many-to-many mapping |
๐ Best Practices
- Always define
mappedBy
on the non-owning side - Use
@JoinColumn
to customize foreign key column names - Avoid
FetchType.EAGER
unless really necessary - Use DTOs for large/complex data instead of directly exposing entities