π 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 (@ManyToOne
with@JoinColumn
). -
The parent (
One
) just references it (@OneToMany(mappedBy = "field")
).
π 2οΈβ£ Example: Department β Employee
- One
Department
has manyEmployees
(@OneToMany
). - Each
Employee
belongs 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! π