601

Hibernate throws this exception during SessionFactory creation:

org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags

This is my test case:

Parent.java

@Entity
public Parent {

 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
 private Long id;

 @OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
 // @IndexColumn(name="INDEX_COL") if I had this the problem solve but I retrieve more children than I have, one child is null.
 private List<Child> children;

}

Child.java

@Entity
public Child {

 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
 private Long id;

 @ManyToOne
 private Parent parent;

}

How about this problem? What can I do?


EDIT

OK, the problem I have is that another "parent" entity is inside my parent, my real behavior is this:

Parent.java

@Entity
public Parent {

 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
 private Long id;

 @ManyToOne
 private AnotherParent anotherParent;

 @OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
 private List<Child> children;

}

AnotherParent.java

@Entity
public AnotherParent {

 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
 private Long id;

 @OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
 private List<AnotherChild> anotherChildren;

}

Hibernate doesn't like two collections with FetchType.EAGER, but this seems to be a bug, I'm not doing unusual things...

Removing FetchType.EAGER from Parent or AnotherParent solves the problem, but I need it, so real solution is to use @LazyCollection(LazyCollectionOption.FALSE) instead of FetchType (thanks to Bozho for the solution).

Jan Nielsen
  • 10,892
  • 14
  • 65
  • 119
blow
  • 12,811
  • 24
  • 75
  • 112
  • 2
    I would ask, what SQL query are you hoping to generate that will retrieve two separate collections simultaneously? The kinds of SQL that would be able to achieve these would either require a cartesian join (potentially highly inefficient) or a UNION of disjoint columns (also ugly). Presumably the inability to achieve this in SQL in a clean & efficient manner influenced the API design. – Thomas W Jan 16 '18 at 00:47
  • @ThomasW These are the sql queries it should generate: `select * from master; select * from child1 where master_id = :master_id; select * from child2 where master_id = :master_id` – nurettin Oct 14 '18 at 12:28
  • 2
    You can get a simillar error if you have more than one `List` with `fetchType` defined for **more than one** `List` – Big Zed Feb 20 '20 at 18:41

18 Answers18

684

I think a newer version of hibernate (supporting JPA 2.0) should handle this. But otherwise you can work it around by annotating the collection fields with:

@LazyCollection(LazyCollectionOption.FALSE)

Remember to remove the fetchType attribute from the @*ToMany annotation.

But note that in most cases a Set<Child> is more appropriate than List<Child>, so unless you really need a List - go for Set

Use with caution

Remember that using a Set won't eliminate the underlying Cartesian Product as described by Vlad Mihalcea in his answer!

luiscla27
  • 4,956
  • 37
  • 49
Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
  • 1
    i'm using hibernate 3.6, i tried your suggest but the problem remains. – blow Dec 02 '10 at 17:48
  • 6
    odd, it has worked for me. Did you remove the `fetchType` from the `@*ToMany` ? – Bozho Dec 02 '10 at 17:51
  • 1
    oh, sorry, ok now works. However what is the reason of this problem? I used fetchtype EAGER a lot of times in equal situation without problem, why now i have this trouble? Thank you. – blow Dec 02 '10 at 19:16
  • 117
    the problem is that the JPA annotations are parsed not to allow more than 2 eagerly loaded collection. But the hibernate-specific annnotations allow it. – Bozho Dec 02 '10 at 23:27
  • 21
    The need for more than 1 EAGER seems totally realistic. Is this limitation just a JPA oversight? What are the concerns I should look for when having muliple EAGERs? – AR3Y35 Jun 17 '12 at 11:18
  • 9
    the thing is, hibernate can't fetch the two collections with one query. So when you query for the parent entity, it will need 2 extra queries per result, which is normally something you don't want. – Bozho Jun 18 '12 at 11:19
  • This problem is exacerbated by JSF that only implements List in its UIData components. Even wrapping a Set in an ArrayList in JSF causes yet other problems, hence Lists linked directly to JPA is what JSF requires. – Darrell Teague Mar 10 '13 at 03:11
  • I only ran into this problem in my JUnit tests. It was unable to build EntityManagerFactory because of this MultipleBagFetchException. This answer solved it! – dvtoever Apr 16 '13 at 09:05
  • 11
    It'd be great to have an explanation as to why this resolves the issue. – Ben Sep 24 '13 at 13:29
  • to be honest, I don't know precisely - hibernate has some internal implementation details that make it possible. Probably different ways of handling (or simply validating?) the two annotations – Bozho Sep 24 '13 at 13:53
  • @Webnet maybe this will make it clearer for you: https://github.com/introproventures/graphql-jpa-query/issues/2 – Peter Catalin Sep 04 '18 at 20:18
  • 1
    Hibernate is a leaky abstraction that just does not work. – sakra Sep 06 '19 at 12:28
  • But I am trying to fetch them lazily, what's the problem of having two collections? Lazily means NOT at the same time, so what's the problem with two lists with no eager setted? – Carlos López Marí Jan 16 '21 at 17:51
  • 1
    This doesn't work if you are fetching the lists with an Entity Graph – Carlos López Marí Jan 17 '21 at 05:28
  • There's undefined behavior for fetching two Sets at the same time. Other users have different errors, but I was getting an StackOverflow error when hibernate was building a HashSet. I had to revert to List just to get it query calls to return. – Code Eyez Feb 02 '23 at 14:47
325

Simply change from List type to Set type.

Use with caution

This solution is not recommended as it won't eliminate the underlying Cartesian Product as described by Vlad Mihalcea in his answer!

luiscla27
  • 4,956
  • 37
  • 49
Ahmad Zyoud
  • 3,474
  • 1
  • 14
  • 4
  • 44
    A List and a Set are not the same thing: a set does not preserve order – Matteo Mar 15 '12 at 15:36
  • 19
    LinkedHashSet preserves order – egallardo May 16 '12 at 00:12
  • 18
    This is an important distinction and, when you think about it, entirely correct. The typical many-to-one implemented by a foreign key in the DB is really not a List, it's a Set because order is not preserved. So Set is really more appropriate. I think that makes the difference in hibernate, though I don't know why. – fool4jesus Dec 06 '12 at 19:38
  • 3
    I was having the same **cannot simultaneously fetch multiple bags** but not because of annotations. In my case, I was doing left joins and disjunctions with the two `*ToMany`. Changing the type to `Set` solved my problem too. Excellent and neat solution. This should be the official answer. – L. Holanda Oct 15 '14 at 20:22
  • 1
    If you want to preserver order you should use `SortedSet`. – Ondrej Bozek Oct 08 '15 at 15:30
  • 3
    @OndrejBozek But what order are you preserving? We are talking about a foreign key relation in the database. The DB can (and will) return the items in the order that happens to be most convenient to it. If you really want to control order, you need to add some ordering rule to the fetch query (not sure if/how it can be done with JPA), and maybe add some index field to sort on. – Stijn de Witt Jan 21 '17 at 11:17
  • 1
    @StijndeWitt yes you can sort yout foreign key relation using `@OrderBy` or (in case of Hibernate) `@SortComparator` annotation. The you need to have `SortedSet`.It's quite common to have your associations sorted. – Ondrej Bozek Jan 25 '17 at 12:19
  • 30
    I liked the answer, but the million dollar question is: Why? Why with Set don't show exceptions? Thanks – Hinotori Jan 31 '17 at 16:56
  • 3
    I have a perfectly valid use case that was blowing up with this same exceptions when using List. I changed the code as Ahmad suggested and now I'm all "Set". :) – bigMC28 Jun 01 '17 at 00:15
  • 1
    I had a similar problem, but I had `Collection` instead of `List`. Anyway, after I changed it to `Set`, the problem was gone. So, thanks! – Dmytro Titov Jul 24 '19 at 12:28
196

Considering we have the following entities:

enter image description here

And, you want to fetch some parent Post entities along with all the comments and tags collections.

If you are using more than one JOIN FETCH directives:

List<Post> posts = entityManager.createQuery("""
    select p
    from Post p
    left join fetch p.comments
    left join fetch p.tags
    where p.id between :minId and :maxId
    """, Post.class)
.setParameter("minId", 1L)
.setParameter("maxId", 50L)
.getResultList();

Hibernate will throw the infamous:

org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags [
  com.vladmihalcea.book.hpjp.hibernate.fetching.Post.comments,
  com.vladmihalcea.book.hpjp.hibernate.fetching.Post.tags
]

Hibernate doesn't allow fetching more than one bag because that would generate a Cartesian product.

The worst "solution"

Now, you will find lots of answers, blog posts, videos, or other resources telling you to use a Set instead of a List for your collections.

That's terrible advice. Don't do that!

Using Sets instead of Lists will make the MultipleBagFetchException go away, but the Cartesian Product will still be there, which is actually even worse, as you'll find out the performance issue long after you applied this "fix".

The proper solution

You can do the following trick:

List<Post> posts = entityManager.createQuery("""
    select distinct p
    from Post p
    left join fetch p.comments
    where p.id between :minId and :maxId
    """, Post.class)
.setParameter("minId", 1L)
.setParameter("maxId", 50L)
.setHint(QueryHints.PASS_DISTINCT_THROUGH, false)
.getResultList();

posts = entityManager.createQuery("""
    select distinct p
    from Post p
    left join fetch p.tags t
    where p in :posts 
    """, Post.class)
.setParameter("posts", posts)
.setHint(QueryHints.PASS_DISTINCT_THROUGH, false)
.getResultList();

In the first JPQL query, distinct DOES NOT go to the SQL statement. That's why we set the PASS_DISTINCT_THROUGH JPA query hint to false.

DISTINCT has two meanings in JPQL, and here, we need it to deduplicate the Java object references returned by getResultList on the Java side, not the SQL side.

As long as you fetch at most one collection using JOIN FETCH, you will be fine.

By using multiple queries, you will avoid the Cartesian Product since any other collection, but the first one is fetched using a secondary query.

There's more you could do

If you're using the FetchType.EAGER strategy at mapping time for @OneToMany or @ManyToMany associations, then you could easily end up with a MultipleBagFetchException.

You are better off switching from FetchType.EAGER to Fetchype.LAZY since eager fetching is a terrible idea that can lead to critical application performance issues.

Conclusion

Avoid FetchType.EAGER and don't switch from List to Set just because doing so will make Hibernate hide the MultipleBagFetchException under the carpet. Fetch just one collection at a time, and you'll be fine.

As long as you do it with the same number of queries as you have collections to initialize, you are fine. Just don't initialize the collections in a loop, as that will trigger N+1 query issues, which are also bad for performance.

Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911
  • Thanks for the shared knowledge. However, `DISTINCT` is performance killer in this solution. Is there a way to get rid of `distinct`? (tried to return `Set<...>` instead, didn't help much) – Leonid Dashko Nov 18 '19 at 11:31
  • 2
    Vlad, thanks for the help I find it really usuful. However, the issue was related to `hibernate.jdbc.fetch_size` (eventually I set it to 350). By the chance, do you know how to optimize nested relations? E.g. entity1 -> entity2 -> entity3.1, entity 3.2 (where entity3.1 / 3.2 are @OneToMany relations) – Leonid Dashko Nov 21 '19 at 12:54
  • Can't we avoid Cartesian Product by using DISTINCT in one single jpql query with `Set`? – Ruslan Jan 28 '20 at 11:26
  • 3
    No, you can not. Think about it in terms of SQL. You cannot JOIN multiple one-to-many associations without generating a Cartesian Product. – Vlad Mihalcea Jan 28 '20 at 11:40
  • What if comments has another collection that you want load with EAGER loading (List). I tried and had the same MultipleBagFetchException problem – Matías W. May 19 '20 at 02:12
  • 1
    You only get a `MultipleBagFetchException` if you issue `JOIN FETCH` twice in a JPQL query. However, the solution in this answer doesn't tell you to do that. If you read the answer carefully, you will see that you achieve the same goal using a single `JOIN FETCH` and an additional secondary query. – Vlad Mihalcea May 19 '20 at 05:56
  • @VladMihalcea In your recommended solution, is there any point to assign posts = .getResultList() in your second query? It worked without this assignment in my case. – Ismail Yavuz Jun 24 '20 at 12:49
  • 1
    @İsmailYavuz It depends on the JIT implementation. If you return the `posts` variable from the currently executing method, then, if you don't reassign the `posts` variable, maybe the JIT will consider that call useless as it doesn't seem to have any side-effect. – Vlad Mihalcea Jun 24 '20 at 13:36
  • 1
    @VladMihalcea If we have deep nesting like post has many postComments has many likes, Can we use list for first layer(postComments) and set for second layer(Likes) and dedup? This worked fine for me. is there an issue? I mean dedup with with set will work for single one to many but not multiple so we can leverate with set in nexted fetches – shiva kumar Jul 15 '20 at 15:35
  • If you are using spring data jpa and writing this query using custom implementation of repository, don't forget to add Transactional annotation to the method. @VladMihalcea Any reason why it gives LazyInitializationException if it's not annotatated with transactional? – JavaLearner Oct 27 '20 at 15:29
  • 6
    You should always havd @Transactional on the service methods calling a Spring Data Jpa Repository. Not doing so is a terrible mistake. – Vlad Mihalcea Oct 27 '20 at 19:29
  • Should the methods inside custom repository implementation also be annotated with Transactional? reference: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#transactions – JavaLearner Oct 28 '20 at 05:52
  • Those are already transactional, but you want to set the Tx at the service layer so all repositories called from a service use the same Tx. – Vlad Mihalcea Oct 28 '20 at 17:53
  • Is there any benefit for using additional secondary query and not `FetchMode.SUBSELECT` – Raj Nov 04 '20 at 07:59
  • 2
    Of course. The query is more obvious and doesn't have the IN clause limit issue. – Vlad Mihalcea Nov 04 '20 at 09:11
  • It would be really helpful if you describe how to do this with the JPA entities, not just in plain hibernate project. – Carlos López Marí Nov 05 '20 at 00:19
  • The `MultipleBagFetchException` is a Hibernate exception. Other JPA provides have other exceptions. – Vlad Mihalcea Nov 05 '20 at 03:56
  • 2
    I was attempting to use this with `@NamedEntityGraph` annotated entity classes. It does not work, unless I remove the graph logic. Is there any merit to the entity graph technique? – Joseph Gagnon Nov 24 '20 at 23:08
  • I think it can work with entity graphs. I'll create a prototype when I'll have some time. – Vlad Mihalcea Nov 25 '20 at 03:37
  • 1
    @VladMihalcea For me it's the same: Not working with EntityGraph attributePaths, for now I'm using the Set aproach (I don't know if it creates cartesian product when used with Entity Graphs) do you think they do? – Carlos López Marí Jan 17 '21 at 04:58
  • 2
    If you fetch two sibling Set associations using any strategy, you'll get a Cartesian Product. If the associations are related, like child amd grandchildren, then you won't get a Cartesian Product. – Vlad Mihalcea Jan 17 '21 at 05:52
  • @VladMihalcea Then, it is safe to say that if I only have ONE attribute path in my EntityGraph, there's no way I'm getting a cartesian product, right? – Carlos López Marí Jan 17 '21 at 14:26
  • 1
    @CarlosLópezMarí JPA associations are fetched via LEFT or INNER joins. So, the only way to generate a Cartesian Product is the same as with plain SQL. After all, it all boils done to SQL. And, when using INNER and LEFT joins, the only way to generate a Cartesian Product is to generate two virtual tables (from intermediate joins) that cannot be associated by following the JOIN condition. – Vlad Mihalcea Jan 17 '21 at 16:53
  • What if you had an additional collection on the `tags` object which you also wanted to initialise? Is it possible (or maybe unwise) to go another level deep? – dre Feb 09 '21 at 14:57
  • Another best option is to use MyBatis for this kind of sceanario – harsha kumar Reddy Apr 27 '21 at 13:06
  • @harshakumarReddy If you think it's that easy to fetch a graph of N-level relations using MyBatis, feel free to add a new answer and show it to us. I'm afraid your "best solution" will end up being more complex than using 2 JPQL queries and relying on the Persistence Context to bind the associations. – Vlad Mihalcea Apr 27 '21 at 13:11
  • 1
    @VladMihalcea I was just suggesting hybrid approach not completely replacing hibernate entirely . i remember that you have mentioned in your blog that for ManytoMany relationship its not good to use List and use Set instead because when we delete one child . all Childs will be deleted along with it and reinserted except the one deleted with is not efficient . can you shed more light on this,here you are saying Sets are not efficient – harsha kumar Reddy Apr 29 '21 at 06:17
  • 1
    @harshakumarReddy Here, I'm not saying that Sets are not efficient. It's just that if you use Sets you don't get the exception, but you still get the Cartesian Product. You can also get the Cartesian Product with MyBatis and fetching a List of sibling children. Also, don't take one piece of advice from a context and generalize it for everything, as it's a bad idea. Use every piece of advice in its original context and you'll be fine. – Vlad Mihalcea Apr 29 '21 at 09:34
  • Your answer is quite opinionated. It can make sense to do a cartesian product or it can be the worst solution, it depends on the data and use case. Additionally using List is not always the best options as you mentioned [it](https://vladmihalcea.com/hibernate-facts-favoring-sets-vs-bags/) :) – Nicolas Labrot Sep 06 '21 at 13:06
  • @NicolasLabrot All of my answers are opinionated. That's because I've actually worked on the Hibernate ORM, so I'm very biased about it. As for that article, I suppose you missed the `The HHH-5855 issue was fixed in Hibernate 5.0.8, so another reason to update.` box on the article ;) – Vlad Mihalcea Sep 06 '21 at 16:50
  • I did not miss it :), does it mean that List should be preferred over Set? – Nicolas Labrot Sep 06 '21 at 18:59
  • 2
    It depends. For embeddable, Set are better. For bidirectional one-to-many associations, it doesn't matter, but List are more versatile. For Many-to-Many, Sets are better. You can find a detailed explanation in my High-Performance Java Persistence book. – Vlad Mihalcea Sep 06 '21 at 20:01
  • @VladMihalcea if i have bidirectional one-to-many can i switch from list to set and that's ok since you say it doesn't matter? Cartesian product will not be a mistake? however, are you saying that I can use the set but still download each collection separately? I have an object that has an on-to-many join and then each has five one-to-many joins. There are many records in the table, but there are single records that meet the join conditions. Is it better to loop through each of the collections separately for the first level join, or change to SET and concatenate all the joins? – turo Dec 15 '21 at 15:29
  • In this example it seems to overwrite the first posts variable, how should we combine the results from each child collection on to the parent? – Georgian Benetatos Jun 15 '22 at 15:09
  • 1
    @VladMihalcea great answer how to do this with query annotations on repository methods in spring boot? – JayD Jun 23 '22 at 06:08
  • 2
    @JayD I'll blog about that in the future. – Vlad Mihalcea Jun 23 '22 at 15:01
  • @VladMihalcea cheers mate looking forward to it – JayD Jun 24 '22 at 06:28
  • It's a good approach, using Spring Data JPA, in service call methods like invoice = invoiceRepository.finById(2L), then invoiceItemList = invoiceItemsRepository.findAllByInvoice(invoice); receiptList = receiptRepository.findAllByInvoice(invoice); then set all together. – EACUAMBA Jan 24 '23 at 14:33
184

Add a Hibernate-specific @Fetch annotation to your code:

@OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
@Fetch(value = FetchMode.SUBSELECT)
private List<Child> childs;

This should fix the issue, related to Hibernate bug HHH-1718

Dave Richardson
  • 4,880
  • 7
  • 32
  • 47
  • 6
    @DaveRlz why subSelect solves this problem. I tried your solution and its working, but dont know how the problem was solved by using this ? – HakunaMatata Aug 10 '13 at 13:34
  • 4
    This is the best answer unless a `Set` really makes sense. Having a single `OneToMany` relationship using a `Set` results in `1+<# relationships>` queries, where as using `FetchMode.SUBSELECT` results in `1+1` queries. Also, using the annotation in the accepted answer (`LazyCollectionOption.FALSE`) causes even more queries to be executed. – mstrthealias Apr 21 '15 at 22:35
  • 1
    FetchType.EAGER is not a proper solution for this. Need to proceed with Hibernate Fetch Profiles and need to solve it – Milinda Bandara Jul 26 '17 at 15:31
  • Every time I forget that annotation name I come back to this answer. ...Every time :) – netikras Aug 25 '17 at 20:16
  • Oh MAN! My controller was getting duplicate object list-nodes back from responses and this answer fixed it! Thank you! @DaveRlz Im using JPA2.2 . – djangofan Oct 15 '17 at 16:15
  • 3
    The two other top answers did not solve my problem. This one did. Thank you! – Blindworks Feb 22 '18 at 11:48
  • 5
    Does anyone know why does SUBSELECT fix it, but JOIN does not? – Innokenty Jan 04 '19 at 16:23
  • Now I get: `LazyInitializationException: failed to lazily initialize a collection of role: xxxx could not initialize proxy - no Session` error. I had to use `EAGER` or `LazyCollection` approach. – WesternGun Apr 14 '20 at 15:20
  • Worth mentioning this is **`org.hibernate.annotations.FetchMode`** *(not `org.hibernate.FetchMode`)* – Steve Chambers Sep 18 '20 at 15:46
  • This should be tha accepted answer, it is not only easy to implement and understand, It is also really well performing! – Carlos López Marí Nov 05 '20 at 00:18
48

After trying with every single option describe in this posts and others, I came to the conclusion that the the fix is a follows.

In every XToMany place @XXXToMany(mappedBy="parent", fetch=FetchType.EAGER) and intermediately after

@Fetch(value = FetchMode.SUBSELECT)

This worked for me

Abimaran Kugathasan
  • 31,165
  • 11
  • 75
  • 105
Javier
  • 597
  • 4
  • 7
17

To fix it simply take Set in place of List for your nested object.

@OneToMany
Set<Your_object> objectList;

And don't forget to use fetch=FetchType.EAGER, It'll work.

There is one more concept CollectionId in Hibernate if you want to stick with list only.

Use with caution

Remember that you won't eliminate the underlying Cartesian Product as described by Vlad Mihalcea in his answer!

luiscla27
  • 4,956
  • 37
  • 49
Prateek Singh
  • 1,106
  • 10
  • 18
6

you can keep booth EAGER lists in JPA and add to at least one of them the JPA annotation @OrderColumn (with obviously the name of a field to be ordered). No need of specific hibernate annotations. But keep in mind it could create empty elements in the list if the chosen field does not have values starting from 0

 [...]
 @OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
 @OrderColumn(name="orderIndex")
 private List<Child> children;
 [...]

in Children then you should add the orderIndex field

Massimo
  • 1,012
  • 14
  • 23
2

When you have too complex objects with saveral collection could not be good idea to have all of them with EAGER fetchType, better use LAZY and when you really need to load the collections use: Hibernate.initialize(parent.child) to fetch the data.

Felipe Cadena
  • 111
  • 1
  • 3
2

We tried Set instead of List and it is a nightmare: when you add two new objects, equals() and hashCode() fail to distinguish both of them ! Because they don't have any id.

typical tools like Eclipse generate that kind of code from Database tables:

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((id == null) ? 0 : id.hashCode());
    return result;
}

You may also read this article that explains properly how messed up JPA/Hibernate is. After reading this, I think this is the last time I use any ORM in my life.

I've also encounter Domain Driven Design guys that basically say ORM are a terrible thing.

rimsky
  • 1,163
  • 3
  • 16
  • 27
1

For me, the problem was having nested EAGER fetches.

One solution is to set the nested fields to LAZY and use Hibernate.initialize() to load the nested field(s):

x = session.get(ClassName.class, id);
Hibernate.initialize(x.getNestedField());
1

At my end, this happened when I had multiple collections with FetchType.EAGER, like this:

@ManyToMany(fetch = FetchType.EAGER, targetEntity = className.class)
@JoinColumn(name = "myClass_id")
@JsonView(SerializationView.Summary.class)
private Collection<Model> ModelObjects;

Additionally, the collections were joining on the same column.

To solve this issue, I changed one of the collections to FetchType.LAZY since it was okay for my use-case.

Goodluck! ~J

JAD
  • 1,096
  • 12
  • 13
1

You can also try to make fetch=FetchType.LAZY and just add @Transactional(readOnly = true) to method where you get child

alxkudin
  • 11
  • 2
0

Commenting both Fetch and LazyCollection sometimes helps to run project.

@Fetch(FetchMode.JOIN)
@LazyCollection(LazyCollectionOption.FALSE)
prisar
  • 3,041
  • 2
  • 26
  • 27
0

One good thing about @LazyCollection(LazyCollectionOption.FALSE) is that several fields with this annotation can coexist while FetchType.EAGER cannot, even in the situations where such coexistence is legit.

For example, an Order may have a list of OrderGroup(a short one) as well as a list of Promotions(also short). @LazyCollection(LazyCollectionOption.FALSE) can be used on both without causing LazyInitializationException neither MultipleBagFetchException.

In my case @Fetch did solve my problem of MultipleBacFetchException but then causes LazyInitializationException, the infamous no Session error.

WesternGun
  • 11,303
  • 6
  • 88
  • 157
0

I solved by annotating:

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
Antonio Petricca
  • 8,891
  • 5
  • 36
  • 74
0

Ok so here's my 2 cents. I had the Fetch Lazy annotations in my Entity but I also duplicated the fetch lazy in the session bean thus causing a multiple bag issue. So I just removed the lines in my SessionBean

criteria.createAlias("FIELD", "ALIAS", JoinType.LEFT_OUTER_JOIN); //REMOVED

And I used Hibernate.initialize on the list I wanted to retrieve after the List parent = criteria.list was called. Hibernate.initialize(parent.getChildList());

0

TLDR: Don't use EAGER. Always fetch things only when you really need them!


A lot of mentions here about FetchType.EAGER and I wanted to go a bit more into detail why this is a bad idea and on what to use alternatively. Hopefully after reading this you realize that really you should absolutely NEVER use FetchType.EAGER.

There is just no good reason to! It's a mayor pitfall that can bite you (or even worse: someone else) down the road. Imagine you chose FetchType.EAGER for a Student -> Teacher relation, because you think every time you need to fetch a Student you also need his Teachers. Now even if you are 100% sure you never need students without teachers right now, you simply can't foresee how requirements change. FetchType.EAGER violates the Open-closed principle! Your code is no longer open for extension - if later the need for loading Students without Teachers arise it's difficult do to that without reworking (and possibly breaking) existing code!

An even bigger problem you have is that you basically created an n+1 select problem for possible future queries, that (rightfully) already fetched another bag in the basic query. Let's say in the future someone wants to load all Students with their grades and there are 30000 of them. Since you told Hibernate to EAGER fetch all Teachers it has to do that. But since you already fetched another "bag" (the grades) within the same query this actually results in 30001 queries - for data that wasn't even needed in that scenario! The first query for loading all Students+Grades and then a separate query for each Student to fetch his teachers. Needless to say that this is horrendous for performance. In my opinion this is the sole reason for people to believe that "Hibernate is slow" - they just don't realize how incredible inefficient it might query stuff in some situations. You really have to be careful with 1:n relations.

3 Alternatives (manually fetch stuff when needed):

  1. Use JOIN FETCH to fetch a collection. To stick with the example SELECT stud FROM STUDENT stud JOIN FETCH stud.teachers would do the trick. This will always fire a single query to fetch students AND teachers. Just be mindful to only fetch one collection that way (explanation would go too far for this answer).
  2. If you use Spring-JPA you can use @EntityGraph(attributePaths = {"teachers"}) to do the same.
  3. You could call Hibernate.initialize(oneStudent.getTeachers()) with the Hibernate-proxy to fetch the relation manually. This will always create a separate query, so don't do it in a loop or you just created a n+1 select problem yourself.

Also one final tip in general: turn the logging for org.hibernate.SQL to DEBUG to see when/what queries are fired and make sure your local dev setup has a reasonable amount of data. When you test your code with only 2 students and don't check the queries that are fired you might miss something like that and end up having issues on real systems with more data.

luiscla27
  • 4,956
  • 37
  • 49
Mario B
  • 2,102
  • 2
  • 29
  • 41
-5

You could use a new annotation to solve this:

@XXXToXXX(targetEntity = XXXX.class, fetch = FetchType.LAZY)

In fact, fetch's default value is FetchType.LAZY too.

leee41
  • 1
  • 2