DEV Community

Hunor Vadasz-Perhat
Hunor Vadasz-Perhat

Posted on

hibernate-010: Bidirectional One-to-Many & Many-to-One in Hibernate

πŸš€ 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 many Employees (@OneToMany).
  • Each Employee belongs to one Department (@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; } 
Enter fullscreen mode Exit fullscreen mode

βœ… 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<>(); } 
Enter fullscreen mode Exit fullscreen mode

βœ… 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) ); 
Enter fullscreen mode Exit fullscreen mode

βœ… 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); 
Enter fullscreen mode Exit fullscreen mode

πŸš€ 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! 
Enter fullscreen mode Exit fullscreen mode

βœ… Get Department from Employee

Employee emp = entityManager.find(Employee.class, 10L); System.out.println(emp.getDepartment().getName()); // βœ… Works! 
Enter fullscreen mode Exit fullscreen mode

βœ… 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)