有两个JPA实体:具有一对多关系的用户和订单。
/**
* User DTO
*/
@Entity
@Table(name="user")
public class User implements Serializable {
private static final long serialVersionUID = 8372128484215085291L;
private Long id;
private Set<Order> orders;
public User() {}
@Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="sequenceUser")
public Long getId() {
return this.id;
}
private void setId(Long id) {
this.id = id;
}
@OneToMany(mappedBy="user", cascade=CascadeType.PERSIST, fetch=FetchType.LAZY)
@LazyCollection(LazyCollectionOption.EXTRA)
public Set<Order> getOrders() {
return orders;
}
public void setOrders(Set<Order> orders) {
this.orders = orders;
}
}
/**
* Order DTO
*/
@Entity
@Table(name="order")
public class Order implements Serializable {
private static final long serialVersionUID = 84504362507297200L;
private Long id;
private User user;
public Order() {
}
@Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="sequenceOrder")
public Long getId() {
return this.id;
}
private void setId(Long id) {
this.id = id;
}
@ManyToOne
@JoinColumn(name="user_id")
public User getUser(){
return user;
}
public void setUser(User user){
this.user = user;
}
}
我在服务层类中使用这些实体,其中每个方法都在事务中运行。一切都很好,除非服务层类的方法必须返回这些实体。
@Transactional(readOnly=true)
public Set<Order> getOrders() {
Set<Order> orders = user.getOrders();
return orders;
}
此方法可以很好地返回数据。但是当我尝试访问收到的集合元素时,我捕获异常:“org.hibernate.LazyInitializationException:无法懒惰地初始化角色集合:package.User.orders,没有会话或会话被关闭”。
所以,它被排除在外。我认为分离结果将解决我的问题,但这样的技巧
@Transactional(readOnly=true)
public Set<Order> getOrders() {
Set<Order> orders = user.getOrders();
for(Order order: orders)
entityManager.detach(order);
return orders;
}
没有改变任何事情:(
对我来说,无论用户是否参加订单,都无关紧要。我只是想使用这个集合,而不是去修改它。
任何人都可以帮助我吗? :)
答案 0 :(得分:7)
此方法可以很好地返回数据。但是当我尝试访问收到的集合元素时,我捕获异常:“org.hibernate.LazyInitializationException:无法懒惰地初始化角色集合:package.User.orders,没有会话或会话被关闭”。
错误是自我解释:您正在尝试加载(延迟)加载的集合,但由于User
实例已分离,因此不再存在活动会话。
所以,它被排除在外。我认为分离结果将解决我的问题,但这样的技巧
这不会改变任何事情。 EntityManager#detach(Object)
方法不会加载任何内容,它会从持久化上下文中删除传递的实体,使其分离。
对我来说,无论用户是否参加订单,都无关紧要。我只是想使用这个集合,而不是去修改它。
您需要将关联设置为EAGER(以便在检索用户时加载Orders)或在检索服务中的用户时使用FETCH JOIN:
SELECT u
FROM User u LEFT JOIN FETCH u.orders
WHERE u.id = :id
我是否正确理解hibernate没有强制加载当前对象的所有惰性关联的标准机制
Hibernate有一个Hibernate.initialize
方法,但这显然不是标准的JPA(更喜欢可移植代码的获取连接)。
我没办法让hibernate忽略当前对象的懒惰关联(将它们设置为null)
什么?无视你的意思是什么?你为什么要那样做?
答案 1 :(得分:1)
发生LazyInitialisationException是因为在事务外部请求了数据。如果您需要这些数据,您必须在交易中请求它 - 在您的情况下,这将在服务方法中。
您可以通过多种方式请求加载数据。最简单的:
for(Order order: orders)
order.getX()
(其中X是Id或版本以外的某些属性)
然而,这将在单独的查询中加载每个订单,如果订单很多,则查询速度很慢。更快的方法是发出返回该用户的所有订单的查询(JP-QL或Criteria)。 (编辑:请参阅Pascal的答案以获得合适的查询。)