How can i get only modified fields from audited entity?
When i use
AuditQuery query = getAuditReader().createQuery().forEntitiesAtRevision(MyEntity.class, revisionNumber).getResultList()
I get all fields; but i want to get only fields modified?
If you are not using the Modified Flags feature on the @Audited
annotation, the only way to obtain that an audited property changed from revision X to revision Y is to actually fetch both revisions and then compare the actual field values between the two object instances yourself.
Assuming you are using the Modified Flags feature on the @Audited
annotation, presently the only way is to fetch the revision numbers for a given entity instance and using those revisions and prior knowledge of the audited columns, use the Envers Query API to ask whether a property changed for that revision.
Obviously this approach is not ideal as it does impose some prior knowledge on the user code's part to know the fields that are audited in order to get the desired result.
List<Number> revisions = reader.getRevisions( MyEntity.class, myEntityId );
for ( Number revisionNumber : revisions ) {
for ( String propertyName : propertyNamesToCheckList ) {
final Long hits = reader.createQuery()
.forRevisionsOfEntity( MyEntity.class, false, false )
.add( AuditEntity.id().eq( myEntityId ) )
.add( AuditEntity.revisionNumber().eq( revisionNumber ) )
.add( AuditEntity.propertyName( propertyName ).hasChanged() )
.addProjection( AuditEntity.id().count() )
.getSingleResult();
if ( hits == 1 ) {
// propertyName changed at revisionNumber
}
else {
// propertyName didn't change at revisionNumber
}
}
}
In Hibernate Envers 6.0, we are introducing a new query that combines forRevisionsOfEntity
with the modified flags query mechanism to obtain not only the revised instances for a given entity class type and primary key, but also a list of fields that were modified at each revision.
The following pseudo code gives an example of the future API:
List results = reader.forRevisionsOfEntityWithChanges( MyEntity.class false )
.add( AuditEntity.id().eq( entityId ) )
.getResultList();
Object previousEntity = null;
for ( Object row : results ) {
Object[] rowArray = (Object[]) row;
final MyEntity entity = rowArray[0];
final RevisionType revisionType = (RevisionType) rowArray[2];
final Set<String> propertiesChanged = (Set<String>) rowArray[3];
for ( String propertyName : propertiesChanged ) {
// using the property name here you know
// 1. that the property changed in this revision (no compare needed)
// 2. Can get old/new values easily from previousEntity and entity
}
}
This feature may be expanded upon or changed as it is going to be considered experimental, but it is something that users have asked for and we at least intend to deliver a first pass at this functionality based on modified flags.
We haven't decided if or how we'd support this for non-modified flags at the moment, so again the only choice there will presently be a brute force bean comparison.
Fore more details on this feature see HHH-8058.