在Hibernate Envers中,无论设置了哪种获取类型,都会延迟加载实体的所有相关集合。因此,当审计具有其他实体集合的实体(当然都是经过审计)时,该集合最初是SetProxy
(在调试时可以看到)。
那么,我该如何初始化该代理呢?使用Hibernate.initialize()
没有效果(我怀疑是因为Hibernate和Envers使用不同的代理对象)。我知道我可以通过迭代它的项目来初始化集合,但这对我来说不是一个选项,因为我在一个实体中有多个集合,更不用说维护问题了。
我需要急切地初始化它们,因为我在Hibernate会话已经关闭的时候访问该集合(将域对象转换为dtos)。
我正在使用Hibernate 3.5.6。
答案 0 :(得分:14)
显然,这是Hibernate Envers的一个开放性问题。他们的JIRA已经存在一个问题:https://hibernate.atlassian.net/browse/HHH-3552。随意投票,也许它会加快速度,当他们看到有些人想要修复它时;)
在Envers团队修复此问题之前,有一个适合我的工作:在集合上调用size()
初始化代理对象。
答案 1 :(得分:4)
到目前为止,我发现初始化Envers代理的最佳解决方法是使用Dozer。将Envers返回的审计实体映射到自身会强制初始化。
例如:
// Assuming you have an initialized EntityManager in entityManager &
// id contains your entity id..
List<Object[]> auditList = (List<Object[]>)AuditReaderFactory.
get(entityManager).
createQuery().
forRevisionsOfEntity(Foo.class, false, true).
add(AuditEntity.id().eq(id)).
getResultList();
// Use a singleton in production apps instead...
DozerBeanMapper mapper = new DozerBeanMapper();
for(Object[] audit : auditList) {
audit[0] = mapper.map(audit[0], Foo.class);
}
// The proxies in the Foo instances in auditList are now initialized
我对这个解决方案不是很满意,但我更喜欢通过手动触摸集合来初始化代理。希望有人提出更好的选择或HHH-3552得到修复!
答案 2 :(得分:-2)
您的设计有问题。
如果你需要在拦截器内初始化它们(我怀疑Envers通过拦截hibernate调用来工作),这意味着你需要事先知道你的域模型。审核应该是域建模的一个完全独立的问题。
说到这里,您可以使用一些通用的反射方法来滚动自己的初始化程序来迭代集合,或者您可以使用 Open-Session-In-View 模式并使其适应Envers (即在你的拦截器内)。
请记住,访问这些项目可能会触发其他查询,如果您分析日志,这可能会造成混淆。
修改强>: 似乎hibernate具有获取配置文件,可以让您在运行时选择获取计划。 请参阅此SO question和docs。