A Guide To MultipleBagFetchException in Hibernate - Baeldung
A Guide To MultipleBagFetchException in Hibernate - Baeldung
(/)
A Guide to
MultipleBagFetchException in
Hibernate
Last modi ed: January 17, 2021
by baeldung (https://www.baeldung.com/author/baeldung/)
Persistence (https://www.baeldung.com/category/persistence/)
Exception (https://www.baeldung.com/tag/exception/)
Hibernate (https://www.baeldung.com/tag/hibernate/)
1. Overview
https://www.baeldung.com/java-hibernate-multiplebagfetchexception 1/10
10/3/2021 A Guide to MultipleBagFetchException in Hibernate | Baeldung
A List:
3. Cause of MultipleBagFetchException
Fetching two or more Bags at the same time on an Entity could form a
Cartesian Product. Since a Bag doesn't have an order, Hibernate would not be
able to map the right columns to the right entities. Hence, in this case, it
throws a MultipleBagFetchException.
Let's have some concrete examples that lead to MultipleBagFetchException.
https://www.baeldung.com/java-hibernate-multiplebagfetchexception 2/10
10/3/2021 A Guide to MultipleBagFetchException in Hibernate | Baeldung
For the rst example, let's try to create a simple entity that has 2 bags and
both with eager fetch type. An Artist might be a good example. It can have a
collection of songs and o ers.
Given that, let's create the Artist entity:
@Entity
class Artist {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@OneToMany(mappedBy = "artist")
private List<Song> songs;
@OneToMany(mappedBy = "artist")
private List<Offer> offers;
Now, we'll be able to create and run a test. Although, if we try to fetch both of
these bag collections at the same time, it would still lead to
MultipleBagFetchException.
4. Simulate a MultipleBagFetchException
https://www.baeldung.com/java-hibernate-multiplebagfetchexception 3/10
10/3/2021 A Guide to MultipleBagFetchException in Hibernate | Baeldung
@Test
public void whenFetchingMoreThanOneBag_thenThrowAnException() {
IllegalArgumentException exception =
assertThrows(IllegalArgumentException.class, () -> {
String jpql = "SELECT artist FROM Artist artist "
+ "JOIN FETCH artist.songs "
+ "JOIN FETCH artist.offers ";
entityManager.createQuery(jpql);
});
assertTrue(actualMessage.contains(expectedMessagePart));
}
5. Domain Model
Before proceeding to possible solutions, let's look at the necessary domain
models, which we'll use as a reference later on.
Suppose we're dealing with a music app's domain. Given that, let's narrow our
focus toward certain entities: Album, Artist, and User.
We've already seen the Artist entity, so let's proceed with the other two
entities instead.
First, let's look at the Album entity:
https://www.baeldung.com/java-hibernate-multiplebagfetchexception 4/10
10/3/2021 A Guide to MultipleBagFetchException in Hibernate | Baeldung
@Entity
class Album {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@OneToMany(mappedBy = "album")
private List<Song> songs;
@ManyToMany(mappedBy = "followingAlbums")
private Set<Follower> followers;
An Album has a collection of songs, and at the same time, could have a set of
followers.
Next, here's the User entity:
@Entity
class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
A User can create many playlists. Additionally, a User has a separate List for
favoriteSongs wherein its order is based on the arrangement index.
https://www.baeldung.com/java-hibernate-multiplebagfetchexception 5/10
10/3/2021 A Guide to MultipleBagFetchException in Hibernate | Baeldung
@Test
public void whenFetchingOneBagAndSet_thenRetrieveSuccess() {
String jpql = "SELECT DISTINCT album FROM Album album "
+ "LEFT JOIN FETCH album.songs "
+ "LEFT JOIN FETCH album.followers "
+ "WHERE album.id = 1";
assertEquals(1, query.getResultList().size());
}
@Test
public void whenFetchingOneBagAndOneList_thenRetrieveSuccess() {
String jpql = "SELECT DISTINCT user FROM User user "
+ "LEFT JOIN FETCH user.playlists "
+ "LEFT JOIN FETCH user.favoriteSongs ";
assertEquals(3, users.size());
}
From the assertion, we can see that we have successfully retrieved all users.
Moreover, we didn't encounter a MultipleBagFetchException. It's because
even though we're fetching two collections at the same time, only
the playlists is a bag collection.
We've seen from the previous workarounds the use of a single JPQL query for
the simultaneous retrieval of collections. Unfortunately, it generates a
cartesian product. We know that it's not ideal. So here, let's solve
the MultipleBagFetchException without having to sacri ce performance.
Suppose we're dealing with an entity that has more than one bag collection. In
our case, it is the Artist entity. It has two bag collections: songs and o ers.
Given this situation, we won't even be able to fetch both collections at the
same time using a single JPQL query. Doing so will lead to a
MultipleBagFetchException. Instead, let's split it into two JPQL queries.
With this approach, we're expecting to fetch both bag collections successfully,
one at a time.
Again, for the last time, let's quickly create an integration test for the retrieval
of all artists:
@Test
public void whenUsingMultipleQueries_thenRetrieveSuccess() {
String jpql = "SELECT DISTINCT artist FROM Artist artist "
+ "LEFT JOIN FETCH artist.songs ";
assertEquals(2, artists.size());
}
From the test, we rst retrieved all artists while fetching its collection of songs.
Then, we created another query to fetch the artists' o ers.
Using this approach, we avoided the MultipleBagFetchException as well as
the formation of a cartesian product.
https://www.baeldung.com/java-hibernate-multiplebagfetchexception 8/10
10/3/2021 A Guide to MultipleBagFetchException in Hibernate | Baeldung
9. Conclusion
In this article, we've explored MultipleBagFetchException in detail. We
discussed the necessary vocabulary and the causes of this exception. We then
simulated it. After that, we talked about a simple music app's domain to have
di erent scenarios for each of our workarounds and ideal solution. Lastly, we
set up several integration tests to verify each of the approaches.
As always, the full source code of the article is available over on GitHub
(https://github.com/eugenp/tutorials/tree/master/persistence-
modules/java-jpa-3).
CATEGORIES
SPRING (HTTPS://WWW.BAELDUNG.COM/CATEGORY/SPRING/)
REST (HTTPS://WWW.BAELDUNG.COM/CATEGORY/REST/)
JAVA (HTTPS://WWW.BAELDUNG.COM/CATEGORY/JAVA/)
SECURITY (HTTPS://WWW.BAELDUNG.COM/CATEGORY/SECURITY-2/)
PERSISTENCE (HTTPS://WWW.BAELDUNG.COM/CATEGORY/PERSISTENCE/)
JACKSON (HTTPS://WWW.BAELDUNG.COM/CATEGORY/JSON/JACKSON/)
HTTP CLIENT-SIDE (HTTPS://WWW.BAELDUNG.COM/CATEGORY/HTTP/)
https://www.baeldung.com/java-hibernate-multiplebagfetchexception 9/10
10/3/2021 A Guide to MultipleBagFetchException in Hibernate | Baeldung
SERIES
JAVA “BACK TO BASICS” TUTORIAL (/JAVA-TUTORIAL)
JACKSON JSON TUTORIAL (/JACKSON)
HTTPCLIENT 4 TUTORIAL (/HTTPCLIENT-GUIDE)
REST WITH SPRING TUTORIAL (/REST-WITH-SPRING-SERIES)
SPRING PERSISTENCE TUTORIAL (/PERSISTENCE-WITH-SPRING-SERIES)
SECURITY WITH SPRING (/SECURITY-SPRING)
ABOUT
ABOUT BAELDUNG (/ABOUT)
THE COURSES (HTTPS://COURSES.BAELDUNG.COM)
JOBS (/TAG/ACTIVE-JOB/)
THE FULL ARCHIVE (/FULL_ARCHIVE)
WRITE FOR BAELDUNG (/CONTRIBUTION-GUIDELINES)
EDITORS (/EDITORS)
OUR PARTNERS (/PARTNERS)
ADVERTISE ON BAELDUNG (/ADVERTISE)
https://www.baeldung.com/java-hibernate-multiplebagfetchexception 10/10