π Bidirectional One-to-Many & Many-to-One in Hibernate
Now, letβs fully explore bidirectional One-to-Many and Many-to-One relationships with real examples, database schema, and queries.
π 1οΈβ£ What is a Bidirectional One-to-Many & Many-to-One?
- One parent entity has multiple child entities (One-to-Many).
- Each child entity belongs to one parent entity (Many-to-One).
-
The "Many" side owns the foreign key, and the "One" side is mapped using
mappedBy.
β Best Practice
-
The child (
Many) owns the relationship (@ManyToOnewith@JoinColumn). -
The parent (
One) just references it (@OneToMany(mappedBy = "field")).
π 2οΈβ£ Example: Department β Employee
- One
Departmenthas manyEmployees(@OneToMany). - Each
Employeebelongs to oneDepartment(@ManyToOne).
β
Step 1: Define @ManyToOne (Owning Side - Employee)
@Entity
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToOne
@JoinColumn(name = "department_id") // β
Foreign key in Employee table
private Department department;
}
β
The department_id foreign key is stored in Employee.
β
Step 2: Define @OneToMany(mappedBy = "department") (Inverse Side - Department)
@Entity
public class Department {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany(mappedBy = "department") // β
Refers to Employee.department
private List<Employee> employees = new ArrayList<>();
}
β
mappedBy = "department" tells Hibernate:
- "The foreign key is already in
Employee.department_id." - "Donβt create an extra join table."
π 3οΈβ£ Database Schema (No Extra Join Table!)
CREATE TABLE department (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255)
);
CREATE TABLE employee (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255),
department_id BIGINT, -- β
Foreign key column
FOREIGN KEY (department_id) REFERENCES department(id)
);
β
The foreign key is only in Employee.department_id, keeping the relationship correct.
π 4οΈβ£ Saving Data in Hibernate
Department department = new Department();
department.setName("IT Department");
Employee emp1 = new Employee();
emp1.setName("Alice");
emp1.setDepartment(department); // β
Set reference in Employee
Employee emp2 = new Employee();
emp2.setName("Bob");
emp2.setDepartment(department);
department.getEmployees().add(emp1); // β
Set reference in Department
department.getEmployees().add(emp2);
entityManager.persist(department);
entityManager.persist(emp1);
entityManager.persist(emp2);
π Now both Department and Employee are correctly linked!
π 5οΈβ£ Querying Both Directions
β Get Employees from Department
Department dept = entityManager.find(Department.class, 1L);
List<Employee> employees = dept.getEmployees();
employees.forEach(emp -> System.out.println(emp.getName())); // β
Works!
β Get Department from Employee
Employee emp = entityManager.find(Employee.class, 10L);
System.out.println(emp.getDepartment().getName()); // β
Works!
β Both queries work because the relationship is bidirectional.
π 6οΈβ£ Summary: One-to-Many & Many-to-One
| Feature | One-to-Many (Department) |
Many-to-One (Employee) |
|---|---|---|
@OneToMany(mappedBy = "department") |
β Yes | β No |
@ManyToOne used? |
β No | β Yes |
@JoinColumn(name = "fk_column") |
β No | β Yes |
| Foreign key location? | β Not in Department
|
β
In Employee.department_id
|
| Extra join table? | β No | β No |
| Reference back? | β Yes | β Yes |
β
Best Practice: Use bidirectional @OneToMany + @ManyToOne to avoid unnecessary join tables and keep data consistent.
Happy coding! π
Top comments (0)