Search code examples
hibernatehibernate-criterialazy-initialization

Hibernate Criteria get associated object for collection


I have the following Hibernate entities: User, Role and Team. There is also the UserTeamRole entity which is basically a connection between a User, his Role and the Team he is in:

@Entity
@Table(name = "user_team_role")
public class UserTeamRole {

    private Long id;
    private User user;
    private Role role;
    private Team team;
    [...]  
}

In my JSF managed bean I need to get the User and all the UserTeamRoles for a particular user designated name that I get in a form. I do that in the UserDAO:

public User getUserByDn(String dn) {
        User result = (User) getSessionFactory().getCurrentSession()
                .createCriteria(User.class)
                .setFetchMode("userTeamRoles", FetchMode.JOIN)
                .add(Restrictions.like("dn", dn)).uniqueResult();
        return result;
    }

I used the FetchMode because otherwise I would get a LazyInitializationException in the bean because the session was closed at the point that I would need to access the collection.

But, after this I also need to loop through this User.userTeamRoles collection and get the name for each role.

When I do this:

    if (null != u.getUserTeamRoles()) {
        for (UserTeamRole urt : u.getUserTeamRoles()) {
            // here get role for every UserTeamRole

            grAuth.add(new SimpleGrantedAuthority(urt.getRole().getName()));
        }
   }

I get an exception:

Caused by: org.hibernate.LazyInitializationException: could not initialize proxy - no Session for the Role entity.

So my question is how can I also get the Role for each UserTeamRole like I did here .setFetchMode("userTeamRoles", FetchMode.JOIN) in getUserByDn.

I tried "chaining" the call to FetchMode but it does not work. I saw you can chain queries on members of associations, but I don't need to query, I just need the Role to be initialized so I can use it further.

I'm using Hibernate 4, Spring 3, JSF 2.

Thanks


Solution

  • You need to create an alias:

    Criteria c = getSessionFactory().getCurrentSession().createCriteria(User.class, "user");
    c.setFetchMode("user.userTeamRoles", FetchMode.JOIN);
    c.createAlias("user.userTeamRoles", "utr", CriteriaSpecification.LEFT_JOIN);
    c.setFetchMode("utr.role", FetchMode.JOIN);
    c.add(Restrictions.like("dn", dn));
    

    The corresponding HQL query is very similar, but much easier to read and understand IMO:

    select distinct user from User user
    left join fetch user.userTeamRoles utr
    left join fetch utr.role
    where user.dn like :dn