Hibernate Many-to-One Relationship
Introduction
In Hibernate, a Many-to-One relationship represents an association where multiple instances of one entity (the “many” side) are related to a single instance of another entity (the “one” side). This is commonly used in database modeling, where many records in one table are associated with a single record in another table. In this article, we’ll cover how to map a Many-to-One relationship in Hibernate, using both unidirectional and bidirectional approaches, with clear examples.
Understanding Many-to-One Relationship in Hibernate
In database terms, a Many-to-One relationship occurs when many rows in one table are related to a single row
in another table. For example, many Order
records can be associated with a single Customer
.
In Hibernate, this relationship can be mapped using annotations, where one entity holds a reference to another entity.
Unidirectional Many-to-One Mapping
In a unidirectional Many-to-One relationship, the “many” side of the relationship holds a reference
to the “one” side, but the reverse is not true. For example, multiple Order
entities can reference
the same Customer
, but the Customer
does not know about the Orders
.
Entity Classes
Let’s define two entities: Order
and Customer
. Each order belongs to a specific customer,
but the customer does not maintain a reference to their orders.
Order.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Entity
@Table(name = "orders")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "order_date")
private LocalDate orderDate;
@Column(name = "total")
private Double total;
@ManyToOne
@JoinColumn(name = "customer_id", referencedColumnName = "id")
private Customer customer;
// Getters, Setters, and Constructors omitted for brevity
}
Customer.java
1
2
3
4
5
6
7
8
9
10
11
12
13
@Entity
@Table(name = "customers")
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
private String name;
// Getters, Setters, and Constructors omitted for brevity
}
Explanation:
- @ManyToOne: Declares that many
Order
entities can be linked to oneCustomer
. - @JoinColumn: Specifies the foreign key (
customer_id
) in theorders
table, which references theid
in thecustomers
table. - The
customer
field in theOrder
entity holds the reference to theCustomer
.
Objects Creation
In this example, we will use the EntityManager
to persist the objects,
though various persistence approaches are also possible.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Customer customer = new Customer();
customer.setName("John Doe");
Order order1 = new Order();
order1.setOrderDate(LocalDate.of(2024, 10, 20));
order1.setTotal(150.75);
order1.setCustomer(customer);
Order order2 = new Order();
order2.setOrderDate(LocalDate.of(2024, 10, 21));
order2.setTotal(200.50);
order2.setCustomer(customer);
entityManager.persist(customer);
entityManager.persist(order1);
entityManager.persist(order2);
Table Structure
Below is an example of how the customers
and orders
tables might look after data is inserted
using the entities described above.
Customers Table:
1
2
3
| id | name |
|-----|------------|
| 1 | John Doe |
Orders Table:
1
2
3
4
| id | order_date | total | customer_id |
|-----|------------|--------|-------------|
| 1 | 2024-10-20 | 150.75 | 1 |
| 2 | 2024-10-21 | 200.50 | 1 |
SQL Queries Generated by Hibernate
If you have hibernate.hbm2ddl.auto=update
or spring.jpa.hibernate.ddl-auto=update
enabled,
you will see the corresponding insert statements reflecting the data added to the tables.
1
2
3
insert into customers (name) values (?);
insert into orders (order_date, total, customer_id) values (?, ?, ?);
insert into orders (order_date, total, customer_id) values (?, ?, ?);
When entityManager.persist(customer)
is called, Hibernate first inserts the Customer
entity
into the customers
table, generating an ID for the customer (e.g., id = 1).
After the customer is persisted, Hibernate inserts the associated Order
entities into the orders
table,
assigning the customer_id
that corresponds to the persisted Customer
.
Bidirectional Many-to-One (One-to-Many) Mapping
Bidirectional relationships are essentially equivalent to the @OneToMany annotation.
For more information, you can read about it here.
Fetching Strategy for @ManyToOne
In a @ManyToOne
relationship, the fetching strategy determines how related entities are retrieved from the database
when the parent entity is fetched. By default, @ManyToOne
uses FetchType.EAGER
,
which means that the associated entity is loaded immediately along with the parent entity.
This can lead to performance issues if the associated entity has a large number of records
or if multiple parent entities are retrieved simultaneously.
If this immediate loading is not required, you can use FetchType.LAZY
,
which defers the loading of the associated entity until it is explicitly accessed.
This approach is generally more efficient, as it reduces the initial amount of data fetched.
-
EAGER Fetching:
1 2 3
@ManyToOne(fetch = FetchType.EAGER) @JoinColumn(name = "person_id") private Person person;
-
LAZY Fetching:
1 2 3
@ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "person_id") private Person person;
Choosing the right fetching strategy depends on the specific use case and the expected usage patterns of the application. Use EAGER fetching when you always need the associated entity, and prefer LAZY fetching when you want to minimize initial data retrieval and only load related entities as needed.
Summary
- In a unidirectional Many-to-One relationship, only the “many” side knows about the “one” side.
- In a bidirectional Many-to-One (also called One-to-Many) relationship, both sides of the relationship know about each other.
- Use
@ManyToOne
to declare the “many” side of the relationship, and@OneToMany(mappedBy = "...")
to define the “one” side in bidirectional mappings. - The fetching strategy can be lazy or eager depending on your performance needs, and the cascade types help manage the lifecycle of related entities.
Conclusion
Hibernate makes it easy to map Many-to-One relationships, allowing you to efficiently manage associations between entities. Depending on your use case, you can implement either unidirectional or bidirectional mappings. With the examples and explanations in this article, you should now be equipped to handle Many-to-One relationships in your Hibernate projects effectively.