jav spring boot mastery

🎯 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:

  • User can have one Profile
  • User can have many Orders
  • Each Order has one User
  • Order can have multiple Product entries 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: Makes User the 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:

  • @OneToMany with mappedBy points to user field in Order.
  • Always use @JoinColumn on 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:

  • @JoinTable defines the mapping table.
  • Use mappedBy to indicate inverse side.

🔄 CascadeType Explained

Cascade TypeDescriptionUse Case
ALLApplies all cascading operations (PERSIST, MERGE, REMOVE, REFRESH, DETACH)Full lifecycle control
PERSISTSaves associated child entities when parent is savedAdd new children with parent
MERGEMerges state of associated child entities when parent is updatedUsed with EntityManager.merge()
REMOVEDeletes associated child entities when parent is deletedCascade delete
REFRESHReloads associated child entities from the databaseKeep in sync with DB
DETACHDetaches child entities when parent is detached from persistence contextUseful 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

Similar Posts