Map Associations with JPA and Hibernate – The Ultimate Guide
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.
Association mappings are one of the key features of JPA and Hibernate. They model the relationship between two database tables as attributes in your domain model. That allows you to easily navigate the associations in your domain model and JPQL or Criteria queries.
JPA and Hibernate support the same associations as you know from your relational database model. You can use:
- one-to-one associations,
- many-to-one associations and
- many-to-many associations.
You can map each of them as a uni- or bidirectional association. That means you can either model them as an attribute on only one of the associated entities or on both. That has no impact on your database mapping, but it defines in which direction you can use the relationship in your domain model and JPQL or Criteria queries. I will explain that in more detail in the first example.
Many-to-One Associations
An order consists of multiple items, but each item belongs to only one order. That is a typical example for a many-to-one association. If you want to model this in your database model, you need to store the primary key of the Order record as a foreign key in the OrderItem table.
With JPA and Hibernate, you can model this in 3 different ways. You can either model it as a bidirectional association with an attribute on the Order and the OrderItem entity. Or you can model it as a unidirectional relationship with an attribute on the Order or the OrderItem entity.
Unidirectional Many-to-One Association
Let’s take a look at the unidirectional mapping on the OrderItem entity first. The OrderItem entity represents the many side of the relationship and the OrderItem table contains the foreign key of the record in the Order table.
As you can see in the following code snippet, you can model this association with an attribute of type Order and a @ManyToOne annotation. The Order order attribute models the association, and the annotation tells Hibernate how to map it to the database.
@Entity public class OrderItem { @ManyToOne private Order order; … }
That is all you need to do to model this association. By default, Hibernate generates the name of the foreign key column based on the name of the relationship mapping attribute and the name of the primary key attribute. In this example, Hibernate would use a column with the name order_id to store the foreign key to the Order entity.
If you want to use a different column, you need to define the foreign key column name with a @JoinColumn annotation. The example in the following code snippet tells Hibernate to use the column fk_order to store the foreign key.
@Entity public class OrderItem { @ManyToOne @JoinColumn(name = “fk_order”) private Order order; … }
You can now use this association in your business code to get the Order for a given OrderItem and to add or remove an OrderItem to or from an existing Order.
Order o = em.find(Order.class, 1L); OrderItem i = new OrderItem(); i.setOrder(o); em.persist(i);
That’s all about the mapping of unidirectional many-to-one associations for now. If you want to dive deeper, you should take a look at FetchTypes. I explained them in detail in my Introduction to JPA FetchTypes.
But now, let’s continue with the association mappings and talk about unidirectional one-to-many relationships next. As you might expect, the mapping is very similar to this one.
Unidirectional One-to-Many Association
The unidirectional one-to-many relationship mapping is not very common. In the example of this post, it only models the association on the Order entity and not on the OrderItem.
The basic mapping definition is very similar to the many-to-one association. It consist of the List items attribute which stores the associated entities and a @OneToMany association.
@Entity public class Order { @OneToMany private List<OrderItem> items = new ArrayList<OrderItem>(); … }
But this is most likely not the mapping you’re looking for because Hibernate uses an association table to map the relationship. If you want to avoid that, you need to use a @JoinColumn annotation to specify the foreign key column.
The following code snippet shows an example of such a mapping. The @JoinColumn annotation tells Hibernate to use the fk_order column in the OrderItem table to join the two database tables.
@Entity public class Order { @OneToMany @JoinColumn(name = “fk_order”) private List<OrderItem> items = new ArrayList<OrderItem>(); … }
You can now use the association in your business code to get all OrderItems of an Order and to add or remove an OrderItem to or from an Order.
Order o = em.find(Order.class, 1L); OrderItem i = new OrderItem(); o.getItems().add(i); em.persist(i);
Bidirectional Many-to-One Associations
The bidirectional Many-to-One association mapping is the most common way to model this relationship with JPA and Hibernate. It uses an attribute on the Order and the OrderItem entity. This allows you to navigate the association in both directions in your domain model and your JPQL queries.
The mapping definition consists of 2 parts:
- the to-many side of the association which owns the relationship mapping and
- the to-one side which just references the mapping
Let’s take a look at the owning side first. You already know this mapping from the unidirectional Many-to-One association mapping. It consists of the Order order attribute, a @ManyToOne annotation and an optional @JoinColumn annotation.
@Entity public class OrderItem { @ManyToOne @JoinColumn(name = “fk_order”) private Order order; … }
The owning part of the association mapping already provides all the information Hibernate needs to map it to the database. That makes the definition of the referencing part simple. You just need to reference the owning association mapping. You can do that by providing the name of the association-mapping attribute to the mappedBy attribute of the @OneToMany annotation. In this example, that’s the order attribute of the OrderItem entity.
@Entity public class Order { @OneToMany(mappedBy = “order”) private List<OrderItem> items = new ArrayList<OrderItem>(); … }
You can now use this association in a similar way as the unidirectional relationships I showed you before. But adding and removing an entity from the relationship requires an additional step. You need to update both sides of the association.
Order o = em.find(Order.class, 1L); OrderItem i = new OrderItem(); i.setOrder(o); o.getItems().add(i); em.persist(i);
That is an error-prone task, and a lot of developers prefer to implement it in a utility method which updates both entities.
@Entity public class Order { … public void addItem(OrderItem item) { this.items.add(item); item.setOrder(this); } … }
That’s all about many-to-one association mapping for now. You should also take a look at FetchTypes and how they impact the way Hibernate loads entities from the database. I get into detail about them in my Introduction to JPA FetchTypes.
Many-to-Many Associations
Many-to-Many relationships are another often used association type. On the database level, it requires an additional association table which contains the primary key pairs of the associated entities. But as you will see, you don’t need to map this table to an entity.
A typical example for such a many-to-many association are Products and Stores. Each Store sells multiple Products and each Product gets sold in multiple Stores.
Similar to the many-to-one association, you can model a many-to-many relationship as a uni- or bidirectional relationship between two entities.
But there is an important difference that might not be obvious when you look at the following code snippets. When you map a many-to-many association, you should use a Set instead of a List as the attribute type. Otherwise, Hibernate will take a very inefficient approach to remove entities from the association. It will remove all records from the association table and re-insert the remaining ones. You can avoid that by using a Set instead of a List as the attribute type.
OK let’s take a look at the unidirectional mapping first.
Unidirectional Many-to-Many Associations
Similar to the previously discussed mappings, the unidirectional many-to-many relationship mapping requires an entity attribute and a @ManyToMany annotation. The attribute models the association and you can use it to navigate it in your domain model or JPQL queries. The annotation tells Hibernate to map a many-to-many association.
Let’s take a look at the relationship mapping between a Store and a Product. The Set products attribute models the association in the domain model and the @ManyToMany association tells Hibernate to map it as a many-to-many association.
And as I already explained, please note the difference to the previous many-to-one mappings. You should map the associated entities to a Set instead of a List.
@Entity public class Store { @ManyToMany private Set<Product> products = new HashSet<Product>(); … }
If you don’t provide any additional information, Hibernate uses its default mapping which expects an association table with the name of both entities and the primary key attributes of both entities. In this case, Hibernate uses the Store_Product table with the columns store_id and product_id.
You can customize that with a @JoinTable annotation and its attributes joinColumns and inverseJoinColumns. The joinColumns attribute defines the foreign key columns for the entity on which you define the association mapping. The inverseJoinColumns attribute specifies the foreign key columns of the associated entity.
The following code snippet shows a mapping that tells Hibernate to use the store_product table with the fk_product column as the foreign key to the Product table and the fk_store column as the foreign key to the Store table.
@Entity public class Store { @ManyToMany @JoinTable(name = “store_product”, joinColumns = { @JoinColumn(name = “fk_store”) }, inverseJoinColumns = { @JoinColumn(name = “fk_product”) }) private Set<Product> products = new HashSet<Product>(); … }
That’s all you have to do to define an unidirectional many-to-many association between two entities. You can now use it to get a Set of associated entities in your domain model or to join the mapped tables in a JPQL query.
Store s = em.find(Store.class, 1L); Product p = new Product(); s.getProducts().add(p); em.persist(p);
Bidirectional Many-to-Many Associations
The bidirectional relationship mapping allows you to navigate the association in both directions. And after you’ve read the post this far, you’re probably not surprised when I tell you that the mapping follows the same concept as the bidirectional mapping of a many-to-one relationship.
One of the two entities owns the association and provides all mapping information. The other entity just references the association mapping so that Hibernate knows where it can get the required information.
Let’s start with the entity that owns the relationship. The mapping is identical to the unidirectional many-to-many association mapping. You need an attribute that maps the association in your domain model and a @ManyToMany association. If you want to adapt the default mapping, you can do that with a @JoinColumn annotation.
@Entity public class Store { @ManyToMany @JoinTable(name = “store_product”, joinColumns = { @JoinColumn(name = “fk_store”) }, inverseJoinColumns = { @JoinColumn(name = “fk_product”) }) private Set<Product> products = new HashSet<Product>(); … }
The mapping for the referencing side of the relationship is a lot easier. Similar to the bidirectional many-to-one relationship mapping, you just need to reference the attribute that owns the association.
You can see an example of such a mapping in the following code snippet. The Set<Product> products attribute of the Store entity owns the association. So, you only need to provide the String “products” to the mappedBy attribute of the @ManyToMany annotation.
@Entity public class Product{ @ManyToMany(mappedBy=”products”) private Set<Store> stores = new HashSet<Store>(); … }
That’s all you need to do to define a bidirectional many-to-many association between two entities. But there is another thing you should do to make it easier to use the bidirectional relationship.
You need to update both ends of a bidirectional association when you want to add or remove an entity. Doing that in your business code is verbose and error-prone. It’s, therefore, a good practice to provide helper methods which update the associated entities.
@Entity public class Store { public void addProduct(Product p) { this.products.add(p); p.getStores().add(this); } public void removeProduct(Product p) { this.products.remove(p); p.getStores().remove(this); } … }
OK, now we’re done with the definition of the many-to-many association mappings. Let’s take a look at the third and final kind of association: The one-to-one relationship.
One-to-One Associations
One-to-one relationships are rarely used in relational table models. You, therefore, won’t need this mapping too often. But you will run into it from time to time. So it’s good to know that you can map it in a similar way as all the other associations.
An example for a one-to-one association could be a Customer and the ShippingAddress. Each Customer has exactly one ShippingAddress and each ShippingAddress belongs to one Customer. On the database level, this mapped by a foreign key column either on the ShippingAddress or the Customer table.
Let’s take a look at the unidirectional mapping first.
Unidirectional One-to-One Associations
As in the previous unidirectional mapping, you only need to model it for the entity for which you want to navigate the relationship in your query or domain model. Let’s say you want to get from the Customer to the ShippingAddress entity.
The required mapping is similar to the previously discussed mappings. You need an entity attribute that represents the association, and you have to annotate it with an @OneToOne annotation.
When you do that, Hibernate uses the name of the associated entity and the name of its primary key attribute to generate the name of the foreign key column. In this example, it would use the column shippingaddress_id. You can customize the name of the foreign key column with a @JoinColumn annotation. The following code snippet shows an example of such a mapping.
@Entity public class Customer{ @OneToOne @JoinColumn(name = “fk_shippingaddress”) private ShippingAddress shippingAddress; … }
That’s all you need to do to define a one-to-one association mapping. You can now use it in your business to add or remove an association, to navigate it in your domain model or to join it in a JPQL query.
Customer c = em.find(Customer.class, 1L); ShippingAddress sa = c.getShippingAddress();
Bidirectional One-to-One Associations
The bidirectional one-to-one relationship mapping extends the unidirectional mapping so that you can also navigate it in the other direction. In this example, you also model it on the ShippingAddress entity so that you can get the Customer for a giving ShippingAddress.
Similar to the previously discussed bidirectional mappings, the bidirectional one-to-one relationship consists of an owning and a referencing side. The owning side of the association defines the mapping, and the referencing one just links to that mapping.
The definition of the owning side of the mapping is identical to the unidirectional mapping. It consists of an attribute that models the relationship and is annotated with a @OneToOne annotation and an optional @JoinColumn annotation.
@Entity public class Customer{ @OneToOne @JoinColumn(name = “fk_shippingaddress”) private ShippingAddress shippingAddress; … }
The referencing side of the association just links to the attribute that owns the relationship. Hibernate gets all information from the referenced mapping, and you don’t need to provide any additional information. You can define that with the mappedBy attribute of the @OneToOne annotation. The following code snippet shows an example of such a mapping.
@Entity public class ShippingAddress{ @OneToOne(mappedBy = “shippingAddress”) private Customer customer; … }
Summary
The relational table model uses many-to-many, many-to-one and one-to-one associations to model the relationship between database records. You can map the same relationships with JPA and Hibernate, and you can do that in an unidirectional or bidirectional way.
The unidirectional mapping defines the relationship only on 1 of the 2 associated entities, and you can only navigate it in that direction. The bidirectional mapping models the relationship for both entities so that you can navigate it in both directions.
The concept for the mapping of all 3 kinds of relationships is the same.
If you want to create an unidirectional mapping, you need an entity attribute that models the association and that is annotated with a @ManyToMany, @ManyToOne, @OneToMany or @OneToOne annotation. Hibernate will generate the name of the required foreign key columns and tables based on the name of the entities and their primary key attributes.
The bidirectional associations consist of an owning and a referencing side. The owning side of the association is identical to the unidirectional mapping and defines the mapping. The referencing side only links to the attribute that owns the association.
Awesome article! Thanks!
Thanks, Pieter
very thank you for all knowle that you have given to me, very thank you one more time. Gad bless you
Hi Varun,
A many-to-oneundefinedone-to-many association is always modeled on as a foreign key on the table that represents the many side. Because of that, Hibernate automatically knows that the foreign key column has to be part of the orderitem table and not the order table.
Regards,
Thorben
Hi,
Thanks for the amazing article. Cleared all my doubts about associations 🙂
Especially the line – "has no impact on your database mapping, but it defines in which direction you can use the relationship in your domain model and JPQL or Criteria queries"
However, I have a question about the uni-directional one-to-many association
Considering the following code snippet.
@OneToMany
@JoinColumn(name = “fk_order”)
private List<OrderItem> items = new ArrayList<OrderItem>();
How does hibernate know that the column "fk_order" is in table OrderItem and not Order.
In the following snippet:
@ManyToOne
@JoinColumn(name = “fk_order”)
private Order order;
Here I kind of understand, mapping is inside OrderItem entity so the column must be inside the associated table.
Thanks once again
@ManyToMany
@JoinTable(name = “store_product”,
joinColumns = { @JoinColumn(name = “fk_store”) },
inverseJoinColumns = { @JoinColumn(name = “fk_product”) })
private Set products = new HashSet();
What would we do here if we didn’t want the whole Product entity, but rather a List of the product names? I’ve looked at @ElementCollection but can’t seem to find an example of it working in a ManyToMany?
Hi Wassa,
in that case, I would recommend writing a use case specific query that gets the required information.
Regards,
Thorben
Hi Thorben,
You completely made my day. So much nicely explained. I was quite confused with this topic but now I am clear. Thanks a lot for such comprehensive explanation
Thank you 🙂
Hi Thorben
What happens when I don’t apply any associations in my entity?
Hi,
May you please explain your question in more details? What do you mean by not applying any associations?
Regards,
Thorben
Thanks for such a great article, clarifying the association mappings in so clear, elegant way!
I’ve wasted much time on googling, reading before I found your article 🙂
Thank you 🙂
In above topic : Bidirectional One-to-One Associations
Customer is owning side and refrence is also created in cutomer table , is it a preferred way or we should store customer_id in shippingAddress table.
You need to model the owning side of the association on the entity that maps the database table that contains the foreign key column. For a one-to-one association, it doesn’t matter on which side you model the foreign key.
Thanks for the great article!
But you haven’t mentioned about the cascading types in @ManyToMany relationship part.
How is Spring Data JPA or Hibernate going to handle the relationships between entities?
Hi,
I explained that in great details in Why you should avoid CascadeType.REMOVE for to-many associations and what to do instead
Regards,
Thorben
Hi,
Great article! Very clear and concise with good examples.
I want to share a “gotcha” for those who are new to these concepts like me. I have a ManyToMany association between User and Role. When accessing the roles for a user, the program was caught in an infinite loop culminating in a StackOverflowError. Digging through the stack trace led me to believe that the equals() and/or hashCode() were improperly implemented and included the associated ManyToMany sets (i.e. User was comparing Roles which was comparing Users, etc). Cleaning up those methods to remove the sets resolved the issue.
Hi Rob,
Yes, that’s a common mistake when implementing equals() and hashCode(). You can learn more about these methods in Ultimate Guide to Implementing equals() and hashCode() with Hibernate.
Regards,
Thorben
HI
Great article.
If I have a requirement similar to country state city with top-down one-to-many which mapping methods should I use?
That depends on the number of elements on the many-site of your associations.
If your database contains several thousand cities for each state, then you should use a unidirectional many-to-one association. I would not model it as a bidirectional association because fetching several thousand entities will create performance issues.
If the many-site doesn’t contain that many elements, I would use a bidirectional many-to-one association.
First of all, thanks for great post.
I have a question, in “Bidirectional Many-to-One Associations” when you save the item object:
Order o = em.find(Order.class, 1L);
OrderItem i = new OrderItem();
i.setOrder(o);
o.getItems().add(i);
em.persist(i);
I think there should be an additional line -> em.persist(o);
Or when you save the item object, hibernate persist “order” object that linked to item object at the same time is that true?
Hi,
the Order object is already a managed entity. That means that Hibernate will automatically detect pending changes during the dirty check and flush them to the database.
Regards,
Thorben
Hi Thorben,
is the case you describe for persisting a Uni-directional One-to-Many relationship really correct?
You write:
Order o = em.find(…);
OrderItem i = new OrderItem();
o.getItems().add(i);
//and then:
em.persist(i); //incorrect?
Shouldn’t the last line be:
em.persist(o) when Cascade Type is PERSIST and:
em.persist(i); em.persist(o); (both) when not?
Hi Jens,
Yes, that part is correct. You don’t need to persist the Order object because it’s already a managed entity. Hibernate will automatically detect all pending changes during the dirty check and flush them to the database.
Regards,
Thorben
Thank you so much
Great Article.
and in onetomany uni directional, is it not required to have cascade ALL?
@OneToMany(cascade=CascadeType.ALL)
No, Cascading is never required. You can, of course, decide to activate it. But you should avoid CascadeType.REMOVE, which is included in ALL, when mapping a to-many association Why you should avoid CascadeType.REMOVE for to-many associations and what to do instead
A really good, easy to understand tutorial!
Great guide! Much easier than official Oracle’s JPA tutorial 🙂
I’ve noticed just one flaw in Unidirectional Many-to-Many Associations section :
@Entity
public class Store {
@ManyToMany
private Set products = new HashSet();
…
}
Shouldn’t be there Set products = new HashSet(); 😛 ?
Thanks, Lukasz.
You’re right, of course. I fixed it 🙂
Good one ! Nicely explained !
Is it a typo in generic and there should be Product?
@Entity
public class Store {
@ManyToMany
private Set products = new HashSet();
…
}
Yes, that’s a typo. Fixed it. Thanks!
Hello Thorben,
thank you for the very useful article! I’d say it’s the best explanation of JPA/Hibernate mappings I’ve read.
I have one question regarding the One-to-One example. It seems to me it’d make more sense to have FK in ShippingAddress table because Customer can exist without ShippnigAddress but ShippingAddress should not exist without Customer. Do you agree with this kind of reasoning?
Sure, you can also model the FK on the ShippingAddress table.
Thanks a million times. So easily explained and so easy to understand
Thanks, for reading it, Sovello 🙂
I need @OneToOne “LAZY” load with JPA, something example?
Hi,
I explain lazy one-to-one mappings and their pitfalls in this article.
Regards,
Thorben
excellent resourse
Hello Thorben,
Could you please provide some guide on how to remove one or some items from items list of a order?
Thank you!