Hibernate Tips: Map an Unidirectional One-to-Many Association Without a Junction Table
Take your skills to the next level!
The Persistence Hub is the place to be for every Java developer. It gives you access to all my premium video courses, monthly Java Persistence News, monthly coding problems, and regular expert sessions.
Hibernate Tips is a series of posts in which I describe a quick and easy solution for common Hibernate questions. If you have a question for a future Hibernate Tip, please leave a comment below.
Question:
My table model contains a normal one-to-many association using a foreign key column on the table that represents the to-many side. When I map this association as a unidirectional one-to-many association with Hibernate, it uses a junction table instead of the foreign key column. How can I fix that?
Solution:
As I explained in great details in my article about best practices for one-to-many association mappings, Hibernate handles unidirectional one-to-many mappings very inefficiently. You should, therefore, try to avoid them and use a bidirectional one-to-many/many-to-one mapping instead.
If there are any reasons that prevent you from using a bidirectional relationship, you can specify the foreign key column with a @JoinColumn annotation. But please be aware that this only prevents Hibernate from using the junction or association table. As you will see in the following example, the mapping is still not as efficient as a bidirectional one.
Add @JoinColumn to avoid a junction table
Here you can see an example of a PurchaseOrder entity that models a unidirectional one-to-many relationship to the Item entity. I added the @JoinColumn annotation to tell Hibernate that it shall use the fk_order column of the Item table to map the association.
@Entity public class PurchaseOrder { @OneToMany @JoinColumn(name = "fk_order") private Set<Item> items = new HashSet<Item>(); ... }
Inefficient association management
When you now persist a new Item entity and add it to the association, you can see that Hibernate no longer uses a junction table to persist the relationship.
15:31:15,788 DEBUG SQL:92 - insert into Item (name, version, id) values (?, ?, ?) 15:31:15,790 DEBUG SQL:92 - update PurchaseOrder set version=? where id=? and version=? 15:31:15,793 DEBUG SQL:92 - update Item set fk_order=? where id=?
But you can also see that Hibernate executes 2 unnecessary SQL UPDATE statements. Hibernate first persists the Item entity without setting the foreign key reference to the PurchasOrder entity. It then updates the PurchaseOrder before it updates the new Item to set the foreign key reference.
The only way to avoid these UPDATE statements is to use a bidirectional or a unidirectional many-to-one mapping. Hibernate then sets the foreign key reference in the INSERT statement without executing any additional SQL statements.
Learn more:
If you want to learn more about JPA’s and Hibernate’s association mapping capabilities, you will enjoy the following articles:
- Ultimate Guide – Association Mappings with JPA and Hibernate
- How to Choose the Most Efficient Data Type for To-Many Associations – Bag vs. List vs. Set
- Best Practices for Many-To-One and One-To-Many Association Mappings
- Hibernate Tips: Easiest way to manage bi-directional associations
Hibernate Tips Book
Get more recipes like this one in my new book Hibernate Tips: More than 70 solutions to common Hibernate problems.
It gives you more than 70 ready-to-use recipes for topics like basic and advanced mappings, logging, Java 8 support, caching, and statically and dynamically defined queries.