26

在 Hibernate Envers 中,实体的所有相关集合都是延迟加载的,而不管设置了什么获取类型。因此,当对具有其他实体集合的实体进行审计查询时(当然都是经过审计的),该集合SetProxy首先是一个(在调试时可以看到)。

那么,如何初始化该代理?使用Hibernate.initialize()没有效果(我怀疑是因为 Hibernate 和 Envers 使用不同的代理对象)。我知道我可以通过迭代它的项目来初始化集合,但这对我来说不是一个选择,因为我在一个实体中有多个集合,更不用说维护问题了。

我需要急切地初始化它们,因为我稍后会在 Hibernate 会话已经关闭(将域对象转换为 dtos)时访问集合。

我正在使用休眠 3.5.6。

4

3 回答 3

17

显然,这是 Hibernate Envers 的一个未解决问题。他们的 JIRA 中已经存在一个问题:https ://hibernate.atlassian.net/browse/HHH-3552 。随意投票,当他们看到有人希望解决这个问题时,也许它会加快速度;)

在 Envers 团队解决此问题之前,有一个对我有用的解决方法:调用size()集合初始化代理对象。

于 2012-04-05T14:04:50.730 回答
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 得到修复!

于 2013-05-09T21:00:55.750 回答
-3

你的设计有问题。

如果您需要在拦截器中初始化它们(我怀疑 Envers 通过拦截休眠调用来工作),这意味着您需要事先了解您的域模型。审计应该完全独立于领域建模。

话虽如此,您可以使用一些通用反射方法来滚动自己的初始化程序来迭代集合,或者您可以使用Open-Session-In-View模式并将其调整为与 Envers 一起使用(即,在您的拦截器内)。

请记住,访问这些项目可能会触发其他查询,如果您分析日志,这可能会造成混淆。


编辑:似乎hibernate有获取配置文件,它可以让你在运行时选择一个获取计划。请参阅此SO 问题文档

于 2011-03-21T18:20:26.777 回答