Hibernate Envers:初始化 Envers 代理

发布于 2024-10-21 13:28:09 字数 368 浏览 7 评论 0原文

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

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

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

我正在使用 Hibernate 3.5.6。

In Hibernate Envers, all related collections of an entity are loaded lazily, regardless of what fetch type is set. So when auditquerying for an entity that has a collection of other entities (both audited, of course), the collection is a SetProxy at first (can be seen when debugging).

So, how do I initialize that proxy? Using Hibernate.initialize() has no effect (I suspect because Hibernate and Envers are using different proxy objects). I know I can initialize the set by iterating over its items, but that isn't an option for me because I have multiple collections in an entity and not to mention the maintenance issues.

I need to initialize them eagerly because I'm accessing the collection at a later point in time when the Hibernate session is already closed (converting the domain objects into dtos).

I'm using Hibernate 3.5.6.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

手长情犹 2024-10-28 13:28:09

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

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

Apparently, this is an open issue with Hibernate Envers. There is already an existing issue in their JIRA: https://hibernate.atlassian.net/browse/HHH-3552. Feel free to vote on it, maybe it will speed things up, when they see that there are some people wanting this to be fixed ;)

Until the Envers team fixes this issue, there is a work around which works for me: Calling size() on the collections initializes the proxy objects.

你的呼吸 2024-10-28 13:28:09

到目前为止,我发现的初始化 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 得到修复!

The best workaround I've found so far for initializing the Envers proxies is to use Dozer. Mapping the audited entity returned by Envers to itself forces the initialization.

For example:

    // 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

I'm not very happy with this solution, but I prefer it over initializing the proxies by manually touching the collections. Hope someone comes up with a better alternative or HHH-3552 gets fixed!

深巷少女 2024-10-28 13:28:09

你的设计有问题。

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

话虽如此,您可以使用一些通用的反射方法来迭代集合,或者您可以使用 Open-Session-In-View 模式并调整它以与 Envers 一起使用(即,在你的拦截器内)。

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


编辑
看来hibernate有fetch profile,它可以让你在运行时选择一个fetch计划。
请参阅此SO问题文档

There's something wrong with your design.

If you need to initialize them inside an interceptor (I suspect Envers works by intercepting hibernate calls), it means that you need to know about your domain model beforehand. Auditing should be a completely independeny concern from domain modeling.

Having this said, you can roll your own initializer using some generic reflection method for iterating the collection, or you can use the Open-Session-In-View pattern and adapt it to work with Envers (ie, inside your interceptor).

Bear in mind that accessing these items will probably trigger other queries, which can be confusing if you analyze the logs.


Edit:
It seems that hibernate has fetch profiles, which can let you choose a fetch plan at runtime.
See this SO question and the docs.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文