Bidirectional One-to-Many & Many-to-One in Hibernate (Department ↔ Employee)
🚀 1️⃣ Bidirectional One-to-Many & Many-to-One
✅ In a bidirectional relationship:
-
The "many" side (
Employee
) owns the relationship (because it holds the foreign key). -
The "one" side (
Department
) is the inverse side and usesmappedBy
to refer to the owning side.
📌 Step 1: @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 column in Employee table
private Department department;
}
✅ The Employee
table gets a department_id
foreign key.
📌 Step 2: @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's `department` field
private List<Employee> employees = new ArrayList<>();
}
✅ mappedBy = "department"
tells Hibernate:
- "The foreign key is already in
Employee.department
." - "Do not create an extra join table."
🔥 Generated SQL (No 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)
);
✅ Correct design! The foreign key is stored in Employee.department_id
, and no join table is created.
🚀 2️⃣ How to Use the Bidirectional Relationship in Java
📌 Saving Data
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);
List<Employee> employees = new ArrayList<>();
employees.add(emp1);
employees.add(emp2);
department.setEmployees(employees); // ✅ Set reference in Department
entityManager.persist(department);
entityManager.persist(emp1);
entityManager.persist(emp2);
✅ Both Department
and Employee
are linked properly.
📌 Querying the Relationship
Get Employees for a Department
Department dept = entityManager.find(Department.class, 1L);
List<Employee> employees = dept.getEmployees();
employees.forEach(emp -> System.out.println(emp.getName()));
Get Department for an Employee
Employee emp = entityManager.find(Employee.class, 10L);
System.out.println(emp.getDepartment().getName());
✅ Both queries work because the relationship is bidirectional.
🚀 3️⃣ Summary: Unidirectional vs. Bidirectional
Feature | Unidirectional @OneToMany
|
Unidirectional @ManyToOne
|
Bidirectional (@OneToMany + @ManyToOne ) |
---|---|---|---|
@OneToMany used? |
✅ Yes (But Creates Extra Table) | ❌ No | ✅ Yes (mappedBy prevents join table) |
@ManyToOne used? |
❌ No | ✅ Yes (Owning Side) | ✅ Yes (Owning Side) |
Uses @JoinColumn ? |
❌ No | ✅ Yes | ✅ Yes (In @ManyToOne ) |
Foreign key in Employee table? | ❌ No | ✅ Yes | ✅ Yes |
Extra join table? | ✅ Yes (Unwanted) | ❌ No | ❌ No |
✅ Best Practice: Use Bidirectional @OneToMany
+ @ManyToOne