Hibernate Relationships
Hibernate Relationships is one of the most important areas because you need to understand both sides: the Java Application and the Relational Database.
In Java, objects can have direct relationships (e.g., Employee → Department). But a relational database doesn't store Java object references. Instead, it uses Primary Keys, Foreign Keys, and Join Tables.
Hibernate's job is to map:
Java Object Relationship
↕
Hibernate
↕
Database Relationship
Before learning annotations, you must understand how relationships are represented in SQL. There are four major relationship types:
- One-to-One
- One-to-Many
- Many-to-One
- Many-to-Many
1. One-to-One
1.1 Meaning & 1.2 Database Representation
One record in Table A is associated with one record in Table B. For example, one Employee has one Passport.
A normal foreign key alone doesn't guarantee one-to-one mapping (as an employee could theoretically have multiple passports linked to them). Therefore, a true one-to-one relationship commonly uses:
FOREIGN KEY + UNIQUE constraint (e.g., employee_id UNIQUE)
1.3 & 1.4 Hibernate Representation & Owning Side
@Entity
public class Employee {
@Id
private Long id;
@OneToOne
@JoinColumn(name = "passport_id")
private Passport passport;
}
This is extremely important: Who owns the relationship? Employee is the owning side because it contains the @JoinColumn. The side containing the foreign-key column generally controls the relationship mapping.
1.5 mappedBy
On the inverse side (Passport), we use @OneToOne(mappedBy = "passport"). This means: "The relationship is already mapped by the 'passport' field in the Employee entity." It does not create another foreign-key column.
2. One-to-Many & 3. Many-to-One
These two are actually reverse perspectives of the same database relationship. For example, One Department has Many Employees.
2.1 Database Representation
Notice something important: The foreign key is on the many side. (e.g., Employee.department_id points to Department.id).
Department Employee
1 *
| |
└──────────────<──────────┘
department_id
This is one of the most important database relationship rules: In a one-to-many relationship, the foreign key normally lives on the many side.
2.2 One-to-Many vs Many-to-One
This confuses many beginners. Don't think they are completely different database relationships. They are usually two Java perspectives of the same table relationship.
Department Employee
1 *
| |
| @OneToMany | @ManyToOne
└──────────────<─────────────┘
4. Why Is @ManyToOne Usually the Owning Side?
Look at the database table for Employee. It contains the department_id. Therefore, the @ManyToOne mapping in the Employee class gets the @JoinColumn and acts as the owning side.
5. Many-to-Many
Now the relationship becomes: Many Employees work on Many Projects. One employee can work on multiple projects, and one project can have multiple employees (Employee * ↔ * Project).
5.1 & 5.2 Why We Need a Join Table
We cannot put a foreign key directly in Employee because a single project_id isn't enough to hold multiple projects. We need a separate association table (Join Table).
Employee
*
|
employee_project ← (Join Table)
|
*
Project
5.3 & 5.4 Hibernate @ManyToMany & @JoinTable
@ManyToMany
@JoinTable(
name = "employee_project",
joinColumns = @JoinColumn(name = "employee_id"),
inverseJoinColumns = @JoinColumn(name = "project_id")
)
private List
- name: The join table name.
- joinColumns: The foreign key pointing from the owning entity (
employee_id). - inverseJoinColumns: The foreign key pointing toward the other entity (
project_id).
6. Database Representation — The Big Picture
This is the part you should memorize conceptually:
One-to-One
Employee 1 ───── 1 Passport
(FK + UNIQUE)
One-to-Many / Many-to-One
Department 1 ───── * Employee
(FK is on the MANY side table)
Many-to-Many
Employee * ───── * Project
(Requires a Join Table)
7. & 8. Core Concepts to Remember
- The Most Important Relationship Rule: In a ONE → MANY relationship, the foreign key normally goes on the MANY side.
- mappedBy: It refers to the Java property name (not the database column name). It tells Hibernate "the other side owns this relationship."
- Owning vs Inverse Side: The entity that has the actual foreign key in its database table generally owns the relationship.
9. Relationship Summary
| Annotation | Meaning | Typical DB Representation |
|---|---|---|
@OneToOne |
One ↔ One | FK + usually UNIQUE constraint |
@OneToMany |
One → Many | FK on the many-side table |
@ManyToOne |
Many → One | FK on the many-side table |
@ManyToMany |
Many ↔ Many | Requires a Join table |
The last three topics—Cascade, Fetch Type (LAZY/EAGER), and N+1 queries—are where Hibernate relationships move from simply knowing annotations to understanding real production behavior!
19. T3 Interview Questions You Should Be Able to Answer
They are usually two perspectives of the exact same database relationship. @OneToMany is viewed from the "One" side (e.g., Department looking at Employees), while @ManyToOne is viewed from the "Many" side (e.g., Employee looking at its Department). The database structure is the same.
It is represented by a Foreign Key column combined with a UNIQUE constraint. This ensures that one record in Table A is associated with exactly one record in Table B.
The owning side is the entity that dictates the relationship mapping, usually because its corresponding database table contains the actual foreign-key column. It is designated by using the @JoinColumn annotation.
mappedBy is used on the inverse side of a bidirectional relationship. It tells Hibernate, "I don't control this relationship; look at the field named X on the other entity for the mapping rules." Because it points to the Java mapping logic on the other entity, it must use the Java property name, not the database column name.
Because a single foreign key column can only point to one record. If an Employee works on multiple Projects, a single project_id column in the Employee table isn't enough. We need a separate table to hold multiple rows mapping various employee_ids to various project_ids.
In a @JoinTable, joinColumns defines the foreign key that points back to the entity that owns the association (the one you are currently writing the annotation in). inverseJoinColumns defines the foreign key pointing to the other (inverse) entity in the relationship.
Comments (0)