π 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! π
Top comments (0)