要获取惰性对象,您需要调用Hibernate.initialize(proxy)
,例如在您的服务类别中:
public <R> R fetchLazy(T entity, Function<T,R> proxyMapper) {
entity = ensureEntityHasOpenedSession(entity);
R proxy = proxyMapper.apply(entity);
Hibernate.initialize(proxy);
return proxy;
}
在服务范围之外,需要调用:
AnotherEntity another = service.fetchLazy(entity, Entity::getAnotherEntity);
现在,问题是为什么这样做有效:
another.getId();
而随后的通话没有:
entity.getAnotherEntity().getId(); // LazyInitializationException
第一次获取后,AnotherEntity
还没有存储在Entity
中吗?我是否总是需要致电
service.fetchLazy(entity, Entity::getAnotherEntity).getSomething();
如果是,Hibernate.initialize(Object)
是在第二次调用时返回缓存的代理还是总是存在另一个数据库访问(查询执行)?
编辑
答案 0 :(得分:1)
您可能正在使用JPA字段访问,即您注释了实体类的Java字段而不是getter。这是Hibernate中对字段访问的已知限制。避免异常或显式初始化的唯一方法是改为使用属性访问。
另请参见以下JIRA问题
答案 1 :(得分:0)
后续调用的问题是@ChristianBeikov指出的与access strategy结合的ensureEntityHasOpenedSession(entity)
方法的实现。
更具体地说,我已将上述方法实现为entityManager.find(entityClass, entityId)
,该方法返回实体的新实例。结果,AnotherEntity
代理在新的实体实例中初始化,而随后的调用则在旧的实体实例中进行操作。自从我使用字段注释以来,任何方法调用都导致了JPA implementation patterns: Field access vs. property access中所述的代理初始化:
Hibernate的延迟加载实现始终会初始化一个延迟 调用该代理上的任何方法时的代理。唯一的例外 这是使用时用@Id注释注释的方法 属性访问。但是,当您使用字段访问时,没有这种方法 并且Hibernate即使在调用以下方法时也会初始化代理 返回实体的身份。
因此LazyInitializationException
(会话关闭且尝试初始化代理的旧实体)。