1

I am using Spring Data and defining following query:

@Query("SELECT u FROM AppUser u LEFT OUTER JOIN fetch u.userRights a LEFT OUTER JOIN fetch u.userGroups g LEFT OUTER JOIN fetch u.userGroups ug LEFT OUTER JOIN FETCH ug.groupRights where u.login = :login")
public Optional<AppUser> findOneWithCompleteRights(@Param("login") String login);

As you might see, I want to get back the logged in user with all his access rights. While starting the spring application, it runs into:

Caused by: javax.persistence.PersistenceException: org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags

I have checked following: Multiple fetches with EAGER type in Hibernate with JPA

If I change all@XXXToMany Types to java.util.Set, it works, but I would like to decide the type on my own...

The other annotations of linked solution (see bottom) seem to be ignored if attached to the @Query method. Second would not make sense, anyway.

  • Load each collection separately using subselect @Fetch(FetchMode.SELECT)
  • Force usage of list instead of bag by adding index column @IndexColumn(name="LIST_INDEX")

Does anybody have another solution rather than setting the type to Set?

Community
  • 1
  • 1
miwoe
  • 757
  • 1
  • 6
  • 17

2 Answers2

0

I had that problem also. It happens when the class to load has more than on property of type List mapped.

You can resolve that, by changing the type of AppUser.userRights and AppUser.userGroups from java.util.List to java.util.Set.

  • Ok, I have already described this solution in my question and asked if there is a different solution :) – miwoe May 28 '16 at 08:01
0

Not using Set here instead of List is exactly what Vlad Mihalcea is describing in this post and in some answers on StackOverflow. In his post he says to use separate queries. But he is giving the solution not with the @Query-Annotation provided by the Spring-Data Project rather using JPQL-statements and the entityManager.

So to achieve the separate Query-Execution I would have thought, that the @Fetch(FetchMode.SELECT) (or SUBSELECT, not yet sure about the difference) would be a proper solution. But not for the @Query-Annotation but for the attribute in the class.

So in your case maybe:

class AppUser {
    ....
    @OneToMany
    @Fetch(FetchMode.SELECT)
    List<UserRights> userRights
    ....
}

But trying that in my own project did not work, either. So another solution might be to somehow create multiple queries in the Statement of the @Query-Annotation, to act according Vlad's suggestion Not sure if that is possible in the Annotation-Parameter itself or if there has to be two Methods with two annotations.

@Query(
    "SELECT u FROM AppUser u 
    LEFT OUTER JOIN fetch u.userRights a 
    LEFT OUTER JOIN fetch u.userGroups g 
    LEFT OUTER JOIN fetch u.userGroups ug 
    LEFT OUTER JOIN FETCH ug.groupRights where u.login = :login"
)
public Optional<AppUser> findOneWithCompleteRights(@Param("login") String login);