问题
I am using Hibernate envers to audit entities in my application. I have separate _audit tables for each entity and then in those tables I have _mod boolean column to indicate if the field has changed or not.
But, I m not getting how to use that column in queries or even how do I get this data in the code?
e.g. following code gives list of audited persons. How do I check which data has changed?
List person = getAuditReader().createQuery()
.forEntitiesAtRevision(Person.class, 12)
.getResultList();
回答1:
You can loop through all the fields of the given entity and find out if that field is changed or not.
Sample code snippet to loop through all the fields of Person entity for revision number 12 and find value of fields which are updated.
public void processFields() throws Exception {
for (Field field : Person.class.getDeclaredFields()) {
final Person changedEntity = fetchEntityForRevisionWhenPropertyChanged(Person.class, 12, field.getName());
if (changedEntity != null) {
// Updated field value for the field. This will list all fields which are changed in given revision.
final Object fieldValue = getField(changedEntity, field.getName());
}
}
}
private <T> Object getField(final T object, final String fieldName) throws Exception {
return new PropertyDescriptor(fieldName, object.getClass()).getReadMethod().invoke(object);
}
private <T> T fetchEntityForRevisionWhenPropertyChanged(final Class<T> entityClass, final int revisionNumber, final String propertyName) {
final List<T> resultList = getAuditReader()
.createQuery()
.forEntitiesModifiedAtRevision(entityClass, revisionNumber)
.add(AuditEntity.property(propertyName).hasChanged())
.addOrder(AuditEntity.id().asc())
.getResultList();
if (CollectionUtils.isNotEmpty(resultList)) {
return resultList.get(0);
} else {
return null;
}
}
In any case if you want to find previous revison of your entity for comparision, you can use following method:
public T getPreviousVersion(final Class<T> entityClass, final Long entityId, final Long currentRevisionNumber) {
final AuditReader reader = AuditReaderFactory.get(entityManager);
final Number previousRevision = (Number) reader.createQuery()
.forRevisionsOfEntity(entityClass, false, true)
.addProjection(AuditEntity.revisionNumber().max())
.add(AuditEntity.id().eq(entityId))
.add(AuditEntity.revisionNumber().lt(currentRevisionNumber))
.getSingleResult();
return Optional.ofNullable(previousRevision)
.map(previousRev -> reader.find(entityClass, entityId, previousRev))
.orElse(null);
}
回答2:
You can try to use Hibernate interceptors. Here is good article about interceptors. With interceptor you can create a callback which would be executed on entity updates/creation etc. It would be smth like this:
public class EntityInterceptor extends EmptyInterceptor {
@Override
public boolean onFlushDirty(Object entity,
Serializable id,
Object[] currentState,
Object[] previousState,
String[] propertyNames,
Type[] types) {
if ( entity instanceof YourEntity ) {
//do update stuff
return true;
}
return false;
}
}
You can compare currentState with previousState to collect information about entity changes and persist it to other tables.
来源:https://stackoverflow.com/questions/36277333/hibernate-envers-how-to-check-if-a-field-has-changed-between-two-revisions