☕
Core Java Roadmap Phase 16
0 / 40 (0%)
☰ Syllabus Index Next: P17 →

JPA / Hibernate ORM & Entity Relationships Architecture

📂 Repository Module: Module 6_ Database and ORM \ Demos_Introduction_to_ORM_JPA & Demos_Entity_Relationships
📖 Textbook Alignment: Volume II — Chapter 5: Database Programming & Entity Persistence
Phase 16

JPA / Hibernate ORM & Entity Relationships Architecture

📂 Module 6_ Database and ORM \ Demos_Introduction_to_ORM_JPA & Demos_Entity_Relationships
📖 Core Java Textbook Alignment: Cay S. Horstmann • Volume II — Chapter 5: Database Programming & Entity Persistence

19.1 Object-Relational Impedance Mismatch, Entity Life Cycle & Relationships

📖 Cay S. Horstmann • Core Java Volume II — Chapter 5, Section 5.1 ("Object-Relational Persistence")
“Writing raw JDBC code requires tedious mapping between relational database rows and Java object graphs. Object-Relational Mapping (ORM) frameworks like Hibernate, adhering to the Java Persistence API (JPA) standard, bridge this impedance mismatch. An entity represents a persistent domain object managed by an EntityManager within a persistence context. Relationships between entities must be modeled with precision to prevent catastrophic performance degradation.”
  • Entity Life Cycle Four States: New/Transient (created in memory, no DB id), Managed (tracked in persistence context, auto-dirtied), Detached (session closed), Removed (scheduled for SQL DELETE).
  • Lazy Loading Axiom Always Default to LAZY: All collection relationships (@OneToMany, @ManyToMany) MUST be FetchType.LAZY to prevent loading entire relational tables into RAM!
💡 Real-World Analogy: The Currency Exchange & The N+1 Restaurant Trap
• Impedance Mismatch: Tables have rows and foreign keys (2D grid). Java has objects, polymorphism, and collections (graph). JPA is the automatic currency exchange translating between Yen and Euros.
• The N+1 Query Trap: Imagine ordering food for 50 people. The waiter brings 1 bill for the group (Query 1), then walks back to the kitchen 50 separate times to fetch each person's fork one by one (N queries)! Solution: Use JOIN FETCH to bring all forks and plates in 1 trip.
⚡ Pro-Tip / Interview Memory Hook: The mappedBy Rule
Who owns the Foreign Key? In a bidirectional @OneToMany / @ManyToOne relationship, the child entity with the @ManyToOne annotation OWNS the foreign key column. The parent entity's @OneToMany MUST have mappedBy = "fieldName", meaning: "I don't own the foreign key column; go look at the child's field!"
📂 Module 6_ Database and ORM/.../Department.java & Employee.java
package com.accenture.ltt.orm;

import jakarta.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
@Table(name = "departments")
public class Department {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    // mappedBy points to the owning field in Employee
    @OneToMany(mappedBy = "department", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private List<Employee> employees = new ArrayList<>();

    public void addEmployee(Employee emp) {
        employees.add(emp);
        emp.setDepartment(this); // Maintain bidirectional sync!
    }
}

@Entity
@Table(name = "employees")
class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String fullName;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "dept_id") // Owning side holding physical foreign key column
    private Department department;

    public void setDepartment(Department dept) { this.department = dept; }
}
👁 Execution & Memory Breakdown • Persistence Context
Step 1: When department.addEmployee(emp) is called inside a managed transaction, Hibernate's dirty-checking engine automatically emits the SQL INSERT statements upon transaction commit.
Step 2: FetchType.LAZY generates dynamic CGLIB proxies so employee records are only queried from the database when department.getEmployees() is explicitly invoked.