Hibernate's implementation of JPA has some quirks, such as not being able to handle the eager fetching of two @OneToMany relationships in a single entity without the use of some work-arounds. Although this article is not about these work-arounds I will give a quick overview of the problem and solution to that problem first, before looking at the specifics of the case where I got the error on a entity with two @ManyToOne.
"cannot fetch simultaneous bags" -Hibernate Devs Overreact
Eagerly populating two @OneToMany collections in single entity does not seem to pose a problem for other JPA implementations, and the Hibernate team seem to be very defensive about this issue whenever it is raised on their forums.
Often, even innocent, inquiries as to the cause of this error results in sarcastic responses from the Hibernate team. I am pretty sure that most people, like myself, accept that hibernate works differently and has a way to address the problem but often users are left to figure the issue out for themselves, like I was years ago.
Basically there are three ways to deal with the problem:
- use lazy loading on all but one of the @OneToMany collections, i.e. (fetch=FetchType.LAZY)
- use Sets instead of Lists i.e Set<Customer> instead of List<Customer>, or
- use the @IndexColumn annotation
The technical details as to why hibernate needs to do this is beyond the scope of this article, but more information can be found at the Hibernate web site. Whilst I have understood this issue for a while, today I came across a problem when I got the "simultaneous bag" error on a class that had only two @ManyToOne relationships!
@ManyToOne throws "cannot fetch simultaneous bags" error
My unit tests starting failing as soon as I added a second @ManyToOne relationship to my, rather simple, entity. I scratched my head for a while and wondered if it was an issue with my custom field name mappings, , as JPA was being implemented on top of an existing schema, and perhaps the error message was erroneous.
As soon as I removed one of the two relationships from the class, the error went away, and the unit tests passed. It also worked if I put "fetch=FetchType.LAZY" on either of the two relationships. Upon examining the referenced classes I found that both had a single @OneToMany relationship defined, that had their collections loading strategy explicitly set to Fetch=FetchType.EAGER.
So it seems that one needs to ensure that the entire entity graph has only one collection that does not have one of the three solutions to multiple @ManyToOne mentioned above implemented. It is not just a restriction on a per entity basis but rather the entire entity tree or graph. Makes sense if you think about it.