Guys, please help me with the following problem.
I have encountered the famous “cannot simultaneously fetch multiple bags” error because I have two Lists in my Parent Entity. Here is a scratch of code:
class Manager{
@OneToMany(cascade = CascadeType.ALL)
@Fetch(FetchMode.JOIN)
@IndexColumn(name = "id")
private List<Action> actions;
@OneToMany(cascade = CascadeType.ALL)
@Fetch(FetchMode.JOIN)
@IndexColumn(name = "id")
private List<Activity> activities;
(...)
}
The mapping is unidirectional.
OK, I have googled that I can use IndexColumn annotation to fix it. I have implemented that, as you see, and now I dont get the mentioned exception. But the problem is that now if I want to get all Managers from db I receive MORE manager instances that really exist!
For example 9 Manager instances if I have only 1 manager and 3 child instances in each collection. I can understand why this happens: Hibernate produces a select which looks like
select ... from Manager this_
left outer join manager_action actions3_ on this_.id=actions3_.Manager_id
left outer join Action action4_ on actions3_.actions_id=action4_.id
left outer join Manager_Activity activities5_ on this_.id=activities5_.Manager_id
left outer join Activity activity6_ on activities5_.activities_id=activity6_.id
… and it really fetches MORE rows than one.
Why this happens?
How can I fix it?
Hibernate makes a cartesian product and doesn’t dedeuplicate in this case. Cartesian products like this (3 actions * 3 activities = 9 rows) only work well with Sets instead of Lists.
Even with two Sets, you should maybe avoid these kinds of cartesian products. Think about it: retrieving just one manager with 100 actions and 100 activities retrieves 10,000 rows from the database. You should perhaps make two queries:
That would make only 200 rows instead of 10,000. And the result will be the same because the activities will be attached to the same Manager instance in the session. It will also avoid the duplication problem you’re having.