Reputation: 500
I am using hibernate-envers
with spring
. Everything works just fine, except when I delete an entity, it does not change the values of updated_by
and updated_date
inside audit table, instead it saves an entity exactly as it was before (just copy) after spring.jpa.properties.org.hibernate.envers.store_data_at_delete=true
.
I have already tried to register listener EventType.PRE_DELETE
, but it didn't help.
Here is my UpdateEntity:
@LastModifiedBy
@Column(nullable = false)
private Long updatedBy;
@LastModifiedDate
@Column(nullable = false)
private Date updatedDate;
How can I capture who deleted and when was deleted inside audit table by modifying columns updated_by
and updated_date
?
Upvotes: 11
Views: 6695
Reputation: 11
Thanks to ŁukaszW, this answer was very useful for me. I have added AuditorAwareUserName
: AuditorAware
to the implementation, and it works perfectly. The "User-Name" is the name of a request header from RequestContextHolder
, and the naming is dynamic.
internal class CustomAuditDeleteStrategy : DefaultAuditStrategy() {
companion object {
private const val REV_TYPE = "REVTYPE"
private const val UPDATED_BY = "updatedBy"
private const val UPDATED_AT = "updatedAt"
private val ZONE_ID = ZoneId.of("Europe/Berlin")
}
private var auditorAwareUserName = AuditorAwareUserName("User-Name")
override fun perform(
session: Session?,
entityName: String?,
configuration: Configuration?,
id: Any?,
data: Any?,
revision: Any?
) {
if (data is Map<*, *>) {
val dataToUpdate = @Suppress("UNCHECKED_CAST") (data as MutableMap<String, Any?>)
if (dataToUpdate[REV_TYPE] == DEL) {
dataToUpdate[UPDATED_BY] = auditorAwareUserName.currentAuditor.get()
dataToUpdate[UPDATED_AT] = ZonedDateTime.now(ZONE_ID).toLocalDateTime()
}
}
super.perform(session, entityName, configuration, id, data, revision)
}
}
Upvotes: 0
Reputation: 21
You can use custom audit strategy:
public class CustomAuditStrategy extends DefaultAuditStrategy {
@Override
public void perform(final Session s, final String e, final AuditEntitiesConfiguration cfg, final Serializable id, final Object data, final Object revision) {
if (data instanceof Map) {
final Map dataToUpdate = (Map)data;
if (dataToUpdate.get("REVTYPE").equals(RevisionType.DEL)) {
dataToUpdate.put("modifiedBy", "test");
dataToUpdate.put("modifiedDate", LocalDateTime.now());
}
}
super.perform(s, e, cfg, id, data, revision);
}
}
And then you should modify hibernate properties:
spring.jpa.properties.org.hibernate.envers.audit_strategy: x.your.CustomAuditStrategy
org.hibernate.envers.store_data_at_delete: true
Upvotes: 2
Reputation: 81907
Looks like you are combining to features: Auditing support and Envers.
Envers records every change to your entity including the delete if configured as you did.
Auditing support traces update and insert timestamps and users. It doesn't work for deletes since there would be nowhere to store that information.
If you want to keep the combination and still make it work you'd need to modify the entity (e.g. setting an extra flag deleting
to true), flush it, maybe even commit it (I'm not sure if that is necessary) and then delete it.
Probably a better approach is using a custom revision object and store the required data there as described in this question and answer: Ways to pass additional data to Custom RevisionEntity in Hibernate Envers?
Upvotes: 7