Подтвердить что ты не робот

Hibernate Envers: Инициализация Envers Proxies

В Hibernate Envers все связанные коллекции объектов загружаются лениво, независимо от того, какой тип выборки задан. Поэтому при проведении аудита для объекта, имеющего коллекцию других объектов (как проверенных, конечно), сборка сначала является SetProxy (это можно увидеть при отладке).

Итак, как мне инициализировать этот прокси? Использование Hibernate.initialize() не имеет эффекта (я подозреваю, что Hibernate и Envers используют разные прокси-объекты). Я знаю, что могу инициализировать набор, повторяя его элементы, но это не вариант для меня, потому что у меня есть несколько коллекций в сущности и не говоря уже о проблемах обслуживания.

Мне нужно инициализировать их с нетерпением, потому что я получаю доступ к коллекции в более поздний момент времени, когда сеанс Hibernate уже закрыт (преобразование объектов домена в dtos).

Я использую Hibernate 3.5.6.

4b9b3361

Ответ 1

По-видимому, это открытая проблема с Hibernate Envers. В их JIRA уже существует проблема: https://hibernate.atlassian.net/browse/HHH-3552. Не стесняйтесь голосовать на нем, возможно, это ускорит процесс, когда они увидят, что есть люди, которые хотят, чтобы это было исправлено;)

Пока команда Envers не исправляет эту проблему, есть работа, которая работает для меня: вызов size() в коллекциях инициализирует прокси-объекты.

Ответ 2

Лучшим обходным решением, которое я нашел до сих пор для инициализации прокси-серверов 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!

Ответ 3

Что-то не так с вашим дизайном.

Если вам нужно инициализировать их внутри перехватчика (я подозреваю, что Envers работает, перехватывая вызовы hibernate), это означает, что вам нужно знать о вашей модели домена заранее. Аудит должен быть полностью независимым от моделирования домена.

Сказав это, вы можете перевернуть свой собственный инициализатор, используя какой-то общий метод отражения для итерации коллекции, или вы можете использовать шаблон Open-Session-In-View и адаптировать его для работы с Envers (т.е. внутри вашего перехватчика).

Имейте в виду, что доступ к этим элементам, вероятно, вызовет другие запросы, которые могут сбивать с толку, если вы анализируете журналы.


Edit: Кажется, что hibernate имеет профили извлечения, которые могут позволить вам выбрать план извлечения во время выполнения. См. Этот вопрос SO и docs.