我有一组像这样的简单模型(为简便起见,省略了getter和setter方法):
@Entity
public class Customer {
@Id
private Integer id;
}
@Entity
public class Order {
@Id
private Integer id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "customer_id")
private Customer customer;
}
我正在尝试使用带有findById方法的Spring JPA存储库(包括客户)加载订单。
首先,我尝试了这一点:
@Transactional
Optional<Order> findById(Integer id) {
return repository.findById(id);
}
但是当我尝试访问Customer时,我遇到了LazyInitializationException:无法初始化代理-没有会话。因此,在引用some other questions之后,我将方法更新为较丑陋,但显式调用了Hibernate.initialize
:
@Transactional
Optional<Order> findById(Integer id) {
return repository.findById(id)
.map( order -> {
Hibernate.initialize(order.getCustomer());
return order;
);
}
但是我仍然得到org.hibernate.LazyInitializationException: could not initialize proxy - no Session
。 repository
是常规的CrudRepository,提供了现成的findById
方法。
如何初始化这个延迟加载的子实体?我的理解是,@Transactional
表示对于整个此方法调用,我仍应处于事务范围之内。下游唯一的事情是存储库本身,它只是一个接口,因此我不确定如何进一步强制此子实体的加载。
可以从数据库中正确检索Order实体及其中的所有其他内容;只有当我尝试获取延迟加载的子实体时,我们才开始出现问题。
我设法做到这一点的唯一方法是使用left join fetch
在存储库中编写一个custom hql method。在这种方法有效的同时,它使我的存储库变得混乱,该方法几乎是另一个方法的重复,而且我敢肯定我实际上并不需要该方法(因此,我宁愿不这样做)。
Spring-Boot 2.1.4.RELEASE,Spring 5.1.6.RELEASE,Hibernate 5.3.7.Final。
答案 0 :(得分:0)
您必须将方法定义为@Transactional
public Optional<Order> findById(Integer id) {
Optional<Order> order = repository.findById(id);
order.ifPresent(o -> Hibernate.initialize(o.getCustomer()));
return order;
}
。请参见spring docs中的“方法可见性和@Transactional”。
这应该有效:
autoload -Uz compinit && compinit