Entity Relationships and JPA Associations [Java Spring Boot Mastery Series – Part 6]
🎯 Objective
Understand how to model relationships between entities in a Spring Boot application using JPA annotations, including:
- One-to-One
- One-to-Many
- Many-to-One
- Many-to-Many
🧱 Example Domain
Let’s model a simple domain with the following:
Usercan have oneProfileUsercan have manyOrders- Each
Orderhas oneUser Ordercan have multipleProductentries and vice-versa
1️⃣ One-to-One: User and Profile
@Entity
public class User {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
@OneToOne(mappedBy = "user", cascade = CascadeType.ALL)
private Profile profile;
// Getters & Setters
}
@Entity
public class Profile {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String address;
@OneToOne
@JoinColumn(name = "user_id")
private User user;
// Getters & Setters
}
🔍 Notes:
@OneToOne: Defines a 1-1 relation.mappedBy: MakesUserthe parent side.cascade = CascadeType.ALL: Saves profile automatically when user is saved.
2️⃣ One-to-Many and Many-to-One: User and Orders
@Entity
public class Order {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String orderNumber;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
// Getters & Setters
}
@Entity
public class User {
// ... previous fields ...
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
private List<Order> orders = new ArrayList<>();
// Getters & Setters
}
🔍 Notes:
@OneToManywithmappedBypoints touserfield inOrder.- Always use
@JoinColumnon the owning side (@ManyToOne).
3️⃣ Many-to-Many: Order and Product
@Entity
public class Product {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToMany(mappedBy = "products")
private List<Order> orders = new ArrayList<>();
// Getters & Setters
}
@Entity
public class Order {
// ... previous fields ...
@ManyToMany
@JoinTable(name = "order_product",
joinColumns = @JoinColumn(name = "order_id"),
inverseJoinColumns = @JoinColumn(name = "product_id")
)
private List<Product> products = new ArrayList<>();
// Getters & Setters
}
🔍 Notes:
@JoinTabledefines the mapping table.- Use
mappedByto indicate inverse side.
🔄 CascadeType Explained
| Cascade Type | Description | Use Case |
|---|---|---|
ALL | Applies all cascading operations (PERSIST, MERGE, REMOVE, REFRESH, DETACH) | Full lifecycle control |
PERSIST | Saves associated child entities when parent is saved | Add new children with parent |
MERGE | Merges state of associated child entities when parent is updated | Used with EntityManager.merge() |
REMOVE | Deletes associated child entities when parent is deleted | Cascade delete |
REFRESH | Reloads associated child entities from the database | Keep in sync with DB |
DETACH | Detaches child entities when parent is detached from persistence context | Useful in detached sessions |
🧭 FetchType Strategy
EAGER: Load immediately with parent (default for @OneToOne & @ManyToOne)LAZY: Load only when accessed (default for @OneToMany & @ManyToMany)
➡️ Best practice: Use LAZY and fetch explicitly with queries.
➡️ Next Up: Part 7 – Custom Queries with Spring Data JPA
