我有以下Hibernate实体:用户,角色和团队。还有一个UserTeamRole实体,它基本上是用户,他的角色和他所在的团队之间的连接:
@Entity
@Table(name = "user_team_role")
public class UserTeamRole {
private Long id;
private User user;
private Role role;
private Team team;
[...]
}
在我的JSF托管Bean中,我需要获取我和用户的所有UserTeamRoles,这些都是我在表单中获得的特定用户指定名称的。我在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;
}
我使用了FetchMode,因为否则会在Bean中得到LazyInitializationException,因为在需要访问集合的时刻会话已关闭。
但是,在此之后,我还需要遍历User.userTeamRoles集合并获取每个角色的名称。
当我这样做时:
if (null != u.getUserTeamRoles()) {
for (UserTeamRole urt : u.getUserTeamRoles()) {
// here get role for every UserTeamRole
grAuth.add(new SimpleGrantedAuthority(urt.getRole().getName()));
}
}
我得到一个例外:
原因:org.hibernate.LazyInitializationException:无法初始化代理-没有会话角色实体。
所以我的问题是,我如何也可以像getUserByDn
中的.setFetchMode(“ userTeamRoles”,FetchMode.JOIN)一样获得每个UserTeamRole的角色。
我尝试“链接”对FetchMode的调用,但是它不起作用。我看到您可以在关联成员上链接查询,但是我不需要查询,我只需要初始化Role,以便可以进一步使用它。
我正在使用Hibernate 4,Spring 3,JSF 2。
谢谢
您需要创建别名:
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));
相应的HQL查询非常相似,但是更容易阅读和理解IMO:
select distinct user from User user
left join fetch user.userTeamRoles utr
left join fetch utr.role
where user.dn like :dn
现在发布答案,以便某人可以获得与Criteria api提取关联的惰性集合相关的帮助。我正在使用hibernate-4.3.11.Final
以下条件查询有效:
Criteria c = getSessionFactory().getCurrentSession().createCriteria(User.class, "user");
c.setFetchMode("user.userTeamRoles", FetchMode.JOIN);
c.createAlias("user.userTeamRoles", "utr", JoinType.LEFT_OUTER_JOIN);
c.setFetchMode("utr.role", FetchMode.JOIN);
c.createAlias("utr.role", "role", JoinType.LEFT_OUTER_JOIN);
c.add(Restrictions.like("dn", dn));
c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); // optional.