🗃️ JPA Q45 / 64

What is mappedBy in JPA relationships?

AI-Powered Answer ✓ Answered

`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 @OneToOne relationship.
  • @OneToMany: Always used on the @OneToMany side of a bidirectional @OneToMany relationship, referencing the @ManyToOne field in the 'many' side entity.
  • @ManyToMany: On one side of a bidirectional @ManyToMany relationship. Either side can be designated as the owning side, but the other side must declare mappedBy.

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.

java
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);
    }
}
java
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 Employee entity is the owning side because its @ManyToOne annotation uses @JoinColumn(name = "department_id") to explicitly define the foreign key column (department_id) in the employee table.
  • The Department entity is the non-owning side. Its @OneToMany annotation uses mappedBy = "department". This tells JPA that the mapping for this relationship is handled by the department field in the Employee entity. Therefore, JPA will not create a employees_department_id foreign key column in the department table (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.