Hibernate Envers: получение правильных ревизий объекта с помощью свойства коллекции

У меня есть две проверяемые сущности, A и B. Сущность A содержит набор сущностей B (помеченных как отношение «один ко многим»). При вставке нового экземпляра A в базу данных все строки A и B имеют одну и ту же ревизию (скажем, ревизию 1). Затем есть обновление для A, которое влияет только на экземпляры объекта B. Таким образом, после обновления объект A все еще находится в версии 1, тогда как объекты B находятся в версии 2 (включая запись MOD в таблице аудита) . В редакции 3 объект A удален. Поскольку коллекция объекта B аннотирована @Cascade, объекты B, принадлежащие A, также удаляются.

Учитывая этот сценарий, как мне создать контрольный запрос с Envers, который получает экземпляр объекта A с обновленными объектами B версии 2? Когда я запрашиваю все версии объекта A, я либо получаю удаленный объект A, который не содержит объектов B (версия 3), либо я получаю A версии 1, которая также содержит объекты B версии 1.

Используя Hibernate 3.6, если это поможет.


person Jim Holden    schedule 12.04.2012    source источник
comment
связанные с stackoverflow.com/questions/10697945/ и stackoverflow.com/questions/10529982/   -  person Jean    schedule 28.06.2012


Ответы (3)


Если вы прочитаете объект A в версии 2, вы получите правильные данные.

В настоящее время нет способа получить список ревизий, в которых изменилась сущность или связанные сущности (как в вашем случае - версия 2 - это изменение только в B, а не в a).

person adamw    schedule 12.04.2012
comment
Я попытался получить A в версии 2, но тогда список результатов аудиторского запроса пуст. Я предположил, что такое поведение правильное, потому что, конечно, в таблице аудита нет записи для A с ревизией 2. - person Jim Holden; 12.04.2012
comment
Хм, нет, это очень странно, на ревизии 2 сущность А существовала. ах! возможно, вы используете неправильный запрос. Первый - найти сущности, которые были изменены в данной ревизии (так, что в rev2 A не был изменен), другой - найти сущности, которые существовали в данной ревизии (тогда A существовал в rev2). - person adamw; 13.04.2012
comment
Спасибо, вот и все. Использование forEntitiesAtRevision () вместо forRevisionsOfEntity () решило мою проблему. - person Jim Holden; 24.04.2012

Я решил аналогичную проблему, добавив скрытое поле даты lastUpdated в свой эквивалент вашей сущности A.

@Entity
public class A {
    private Date lastModified;
    @OneToMany(mappedBy = "a", cascade = CascadeType.ALL )
    private List<B> blist;
    public void touch(){
        lastModified=new Date();
    }
}

Затем в связанных объектах (например, в поле B) я добавил следующее:

public class B {
    @ManyToOne
    private A a; 

    @PreUpdate
    public void ensureParentUpdated(){
        if(a!=null){
            a.touch();
        }
    }
}

Это гарантирует, что ревизия добавляется к A всякий раз, когда ревизия добавляется к B, даже если для этого требуется настраиваемый код во многих сущностях.

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

person Jean    schedule 28.06.2012

В Hibernate мы могли контролировать загрузку дочерних элементов, указав lazy. Итак, вам нужно добавить следующую строку в определение вашего класса в конфигурации гибернации, чтобы она загружала все ассоциации в обоих случаях чтения / записи.

<cache usage="read-write"/>

Если вы отметили CacheMode.REFRESH, он будет записывать элементы в кеш второго уровня. Не читать из кеша второго уровня.

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

person Phani    schedule 12.04.2012
comment
Вы не поняли мою проблему? - person Jim Holden; 12.04.2012
comment
Я попытался понять смысл этого вопроса, но если вы думаете, что я понял это наоборот ... то, пожалуйста, вы можете выразить это коротко, если это возможно. - person Phani; 12.04.2012