Foo看起来里面有这个:
@ManyToMany private Set<User> favouritedBy;
当用户拥有此功能时:
@ManyToMany(mappedBy = "favouritedBy") private Set<Foo> favourites = new HashSet<Foo>(); public Set<Foo> getFavourites() { return favourite; }
fooService拥有此功能,可以通过tranactional方法在打开会话时访问lazyloaded集合:
@Transactional(readOnly = true) public Set<Foo> getFavourites(User user) { user = dao.get(User.class, user.getId()); //the dao gets a session Set<Foo> favourites = user.getFavourites();//but the session is not here and the exception is thrown? return favourties; }
编辑 无需使用标准即可解决此问题:
Set<Foo> favourites = new HashSet<Foo>(user.getFavourites());
这用标准解决了
Session session = sessionFactory.getCurrentSession(); final Criteria crit = session.createCriteria(Foo.class); crit.setFetchMode("favourites", FetchMode.JOIN); crit.add(Property.forName("id").eq(id)); return (Foo) crit.uniqueResult();
默认FetchType的ManyToMany是LAZY和Hibernate文档与懒惰协会合作明确调用这种访问是错误的。只有在会话仍处于打开状态时,才能与延迟关联的对象进行交互。文档的该部分还提供了访问对象的这种延迟关联成员的替代方法。我们更喜欢JOIN在应用程序中按照所使用的标准指定获取方式
FetchType
ManyToMany
LAZY
JOIN
编辑 :
Set<Foo> favourites = user.getFavourites();
上面的语句实际上并不返回包含所有Foo对象的集合。它只是一个代理。Foo仅当像这样访问集合中的元素时才提取实际对象favorites.iterator()。显然,此操作发生在您的getFavorites()方法之外。但是该方法@Transactional上的注释getFavorites()指示该方法结束时将关闭会话。
Foo
favorites.iterator()
getFavorites()
@Transactional
因此,在收藏夹集上调用方法时,会话已经关闭,因此是异常。
为了解决这个问题,您应该使用Criteria对象检索用户并指定提取类型,JOIN以便在返回的User对象中填充Foo对象。