Есть несколько способов выполнить то, что вы просите, но в основном это зависит от версии Hibernate и Envers, которые вы используете. Если вы используете Hibernate 5.2 и более ранние версии, вам придется выполнить дополнительную обработку кода, чтобы определить, какую информацию вы хотите.
Я предполагаю, что у вас есть первичный ключ для сущности, которая вас интересует.
List results = AuditReaderFactory.get( session ).createQuery()
.forRevisionsOfEntity( YourEntityClass.class, false, true )
.add( AuditEntity.id().eq( entityId ) )
.addOrder( AuditEntity.revisionNumber().asc() )
.getResultList();
Этот запрос фактически возвращает List<Object[]>
, поскольку второй аргумент forRevisionsOfEntity
равен false. Если бы значение этого аргумента было истинным, возвращение было бы List<YourEntityClass>
.
Исходя из этого, каждая запись в List
является массивом объектов на основе следующей конфигурации:
- Индекс 0 - экземпляр
YourEntityClass
в этой ревизии
- Индекс 1 - конкретная реализация сущности ревизии (подробнее об этом позже).
- Index 2 - значение перечисления
RevisionType
, либо ADD
, MOD
, либо DEL
. Если бы третий аргумент forRevisionsOfEntity
был ложным, никогда не было бы типов DEL
.
В этот момент логика становится примерно такой:
YourEntityClass previousInstance = null;
for ( int i = 0; i < results.size(); ++i ) {
Object[] row = (Object[]) results.get( i );
if ( previousInstance == null ) {
// this is the first revision, consider nothing changed here
// so store a reference to it for the next row.
previousInstance = row[0];
}
else {
final YourRevisionEntity revEntity = (YourRevisionEntity) row[1];
final String userName = revEntity.getUserName();
final long revisionTimestamp = revEntity.getTimestamp();
final YourEntityClass currentInstance = (YourEntityClass) row[0];
List<Action> actions = resolveActions( previousInstance, currentInstance );
// build your things
previousInstance = currentInstance;
}
}
Основной вывод здесь заключается в том, что в вашем методе resolveActions
вы, в основном, используете что-то вроде отражения или библиотеки Java-объектов diff для определения изменений между двумя экземплярами. Если вы используете идею withModifiedFlag
, вы можете выполнить запрос для каждого свойства, но это может обременительно для вашей системы, если рассматриваемый тип сущности имеет множество столбцов или если у вас, как правило, множество ревизий.
Если вы используете Hibernate 5.3, мы добавили удобный метод, который немного упрощает этот процесс, но он также основан на концепции withModifiedFlag
. В этом конкретном случае вы изначально запустите слегка измененную версию исходного запроса
List results = AuditReaderFactory.get( session ).createQuery()
.forRevisionsOfEntityWithChanges( YourEntityClass.class, false, true )
.add( AuditEntity.id().eq( entityId ) )
.addOrder( AuditEntity.revisionNumber().asc() )
.getResultList();
Этот запрос возвращает тот же тип массива, что и упомянутый выше 5.2, за исключением того, что он содержит один дополнительный объект в массиве объектов:
- Указатель 3 - Коллекция строк, свойства которых изменились.
Хорошая идея об этом новом подходе состоит не в том, чтобы использовать отражение или какую-либо библиотеку различий, как я упоминал для resolveActions
, теперь вы уже точно знаете, какие свойства были изменены, просто нужно получить только эти конкретные значения из экземпляра объекта, который является супер тривиальным.
Этот последний подход все еще @Incubating
, поэтому он считается экспериментальным. Я мог бы потенциально увидеть изменение индекса 3 таким образом, что вы получите обратно Tuple<String,Object>
, где оно содержит имя свойства / поля, потенциально со значением, что делает его гораздо более простым для использования пользователями.