【问题标题】:Clear Hibernate PersistentSet in persistent-to-detached object清除持久到分离对象中的 Hibernate PersistentSet
【发布时间】: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


【解决方案1】:

有两个(或三个)选项:

  1. collection filter
  2. 使用查询获取集合
  3. 在内存中进行过滤

第一个选项是最复杂的。您必须在需要时以编程方式在休眠会话上启用过滤器。从那时起,集合将像只有接受的朋友在其中一样运行,无需编写特定的查询。

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

第三点很明显。获取所有朋友并在内存中过滤。如果用户有许多未接受的朋友,这可能会影响性能。

【讨论】:

  • 谢谢马腾。我不知道 Hibernate 过滤器,它们是我正在寻找这种情况的完美解决方案。
猜你喜欢
  • 1970-01-01
  • 2018-06-09
  • 2018-01-25
  • 2012-05-14
  • 1970-01-01
  • 2016-02-17
  • 2014-10-13
  • 1970-01-01
  • 2011-12-28
相关资源
最近更新 更多