在持久性到分离的对象中清除Hibernate PersistentSet

时间:2014-12-19 13:44:16

标签: hibernate nhibernate-mapping

情景:

两个映射类。

@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()时出现问题,然后执行Lazy初始化并覆盖当前的Friends Set状态。

为了避免这种情况,在加载之后,我将用户对象从Hibernate Session中分离出来。

super.getCurrentSession().evict(user);

但是,稍后,尽管Friends Set之前已经初始化,但我得到一个LazyInitializationException并且丢失了朋友集。

我怎样才能避免这种情况并保持好友集数据避免延迟初始化? (我不能改变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();
}

工作正常。 :)

1 个答案:

答案 0 :(得分:1)

有两个(或三个)选项:

  1. collection filter
  2. 使用查询来获取集合
  3. 在内存中进行过滤
  4. 第一种选择是最复杂的。您需要在需要时以编程方式在hibernate会话上启用过滤器。从那时起,该集合将像只有被接受的朋友一样运行,不需要编写特定的查询。

    第二个选项是编写一个查询,该查询只为用户提取已接受的朋友并返回列表。此列表既不附加到用户也不附加到会话(尽管列表中的用户是),因此您不会有懒惰的初始化问题。这可能是最容易实现的。

    第三是显而易见的。获取所有朋友并在内存中过滤。如果用户有许多未被接受的朋友,这可能会受到影响。