What is mappedBy in JPA relationships?
`mappedBy` is a crucial attribute in JPA used to define the non-owning side of a bidirectional relationship. It signifies which entity's field is responsible for managing the foreign key in the database, preventing redundant mappings and ensuring a clean schema.
What is `mappedBy`?
mappedBy is an attribute within relationship annotations like @OneToOne, @OneToMany, and @ManyToMany. It is always specified on the inverse (non-owning) side of a bidirectional relationship and refers to the field or property on the owning side that maps the relationship.
Its primary function is to declare that the relationship mapping is already handled by another field in the associated entity. This tells JPA not to create a separate foreign key column for this side of the relationship, as one already exists (or will be created) on the owning side.
Why use `mappedBy`?
- Avoids Redundant Mappings: Prevents JPA from creating an additional, often unnecessary, foreign key column on the inverse side of the relationship, which would lead to a more complex and potentially inconsistent database schema.
- Defines Owning Side: Clearly designates the owning side of the relationship. The owning side (the one without
mappedBy) is responsible for managing the foreign key and persisting relationship changes to the database. - Simplifies Database Schema: Leads to a cleaner and more intuitive database schema with a single, clear foreign key managing each relationship.
- Prevents Duplicate Joins: Helps JPA understand the relationship's structure, which can optimize queries by avoiding unnecessary joins.
When is `mappedBy` used?
@OneToOne: On the non-owning side of a bidirectional@OneToOnerelationship.@OneToMany: Always used on the@OneToManyside of a bidirectional@OneToManyrelationship, referencing the@ManyToOnefield in the 'many' side entity.@ManyToMany: On one side of a bidirectional@ManyToManyrelationship. Either side can be designated as the owning side, but the other side must declaremappedBy.
Example: Department (One) to Employee (Many)
Consider a scenario where a Department can have many Employees, and an Employee belongs to one Department. In this common OneToMany/ManyToOne relationship, the Employee entity typically owns the foreign key to Department.
package com.example.model;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
// Department.java (Non-owning side of @OneToMany, but owns collection)
@Entity
public class Department {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
// 'mappedBy = "department"' indicates that the 'department' field
// in the Employee entity is responsible for mapping this relationship.
// Department is the non-owning side of the foreign key.
@OneToMany(mappedBy = "department", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Employee> employees = new ArrayList<>();
public Department() {}
public Department(String name) { this.name = name; }
// Getters and setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public List<Employee> getEmployees() { return employees; }
public void setEmployees(List<Employee> employees) { this.employees = employees; }
// Helper methods for bidirectional synchronization
public void addEmployee(Employee employee) {
employees.add(employee);
employee.setDepartment(this);
}
public void removeEmployee(Employee employee) {
employees.remove(employee);
employee.setDepartment(null);
}
}
package com.example.model;
import javax.persistence.*;
// Employee.java (Owning side of @ManyToOne, manages the foreign key)
@Entity
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
// Employee is the owning side because it contains the @JoinColumn
// which defines the foreign key column (department_id) in the Employee table.
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "department_id") // This defines the foreign key column
private Department department;
public Employee() {}
public Employee(String name, Department department) {
this.name = name;
this.department = department;
}
// Getters and setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Department getDepartment() { return department; }
public void setDepartment(Department department) { this.department = department; }
}
In this example:
- The
Employeeentity is the owning side because its@ManyToOneannotation uses@JoinColumn(name = "department_id")to explicitly define the foreign key column (department_id) in theemployeetable. - The
Departmententity is the non-owning side. Its@OneToManyannotation usesmappedBy = "department". This tells JPA that the mapping for this relationship is handled by thedepartmentfield in theEmployeeentity. Therefore, JPA will not create aemployees_department_idforeign key column in thedepartmenttable (which would be redundant).
By using mappedBy, we ensure that changes to the relationship are consistently managed through the owning Employee entity, leading to a single, well-defined foreign key in the database.