【发布时间】:2014-12-19 13:44:15
【问题描述】:
场景:
两个映射类。
@Entity
@Table(name = "user")
public class User implements Serializable {
...
@OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
private Set<UserFriend> friends = new HashSet<>();
...
}
@Entity
@Table(name = "user_friend")
public class UserFriend implements Serializable {
...
@ManyToOne
@JoinColumn(name = "user_id", nullable = false)
private User user;
...
}
最常用的方法是获取所有朋友,但在一种特殊情况下,我只想获取已接受的朋友。为了获得这种方法,在我的 DAO 方法中,我正在做下一个。
Criteria criteria = this.getCurrentSession().createCriteria(User.class)
.createAlias("userAccount", "ua")
.add(Restrictions.like("ua.email", email).ignoreCase())
.createCriteria(
"friends",
"f",
JoinType.LEFT_OUTER_JOIN,
Restrictions.eq("accept", true))
.setCacheRegion(CACHE_REGION)
.setCacheable(true);
User user = (User) criteria.uniqueResult();
这工作正常。
Hibernate: select ... from user this_
left outer join user_friend fr2_ on this_.id=fr2_.user_id and ( fr2_.accept=? )
left outer join user user9_ on fr2_.user_id=user9_.id
inner join user_account ua1_ on this_.id=ua1_.user_id where lower(ua1_.email) like ?
当从@Transactional 范围内的另一个站点调用 user.getFriends() 时出现问题,然后执行延迟初始化并覆盖当前的 Friends Set 状态。
为了避免这种情况,在加载后,我将用户对象从 Hibernate Session 中分离出来。
super.getCurrentSession().evict(user);
但是,后来,虽然 Friends Set 之前已经初始化过了,但是我得到了一个 LazyInitializationException 并且丢失了 Friend Set。
我怎样才能避免这种情况并保持朋友集数据避免延迟初始化? (我不能改变 EAGER 而不是 LAZY)。
基于@Maarten 响应的解决方案
@FilterDef(
name = "friendStatus",
parameters = {@ParamDef(name = "status", type = "boolean")})
public class User implements Serializable {
...
@OneToMany(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
@Filter(name = "friendStatus", condition = "accept = :status")
private Set<UserFriend> friends = new HashSet<>();
...
}
在 DAO 方法中。
public User getUserByEmailWithValidFriends(String email) {
super.getCurrentSession()
.enableFilter("friendStatus").setParameter("status", true);
Criteria criteria = super.getCurrentSession()
.createCriteria(User.class)
.createAlias("userAccount", "ua")
.add(Restrictions.like("ua.email", email).ignoreCase())
.setCacheRegion(CACHE_REGION)
.setCacheable(true);
return criteria.uniqueResult();
}
工作正常。 :)
【问题讨论】:
-
您的查询似乎有些奇怪:用户与 user_friend 加入并再次返回,但在两种情况下都使用相同的条件 (user.id = user_friend.user_id)。这应该导致每个用户只与自己成为朋友。
标签: hibernate nhibernate-mapping