Create a revision when an entity is locked with OPTIMISTIC_FORCE_INCREMENT (even if no property has changed)

Description

In my project, only the root of my object-graph/aggregate has a @Version property.
Each time any child entity is modified, the root is locked with OPTIMISTIC_FORCE_INCREMENT to force the version to change.
(I am using something similar as described in https://vladmihalcea.com/2016/08/30/how-to-increment-the-parent-entity-version-whenever-a-child-entity-gets-modified-with-jpa-and-hibernate)
I do that so that no concurrent modification can happen on the same aggregate (I don't want people modifying 2 different child entities at the same time and bypassing invariants enforced by the root).

My problem is when a child entity is modified, a new revision is only created for the child but not for the root.
As I treat my aggregate as a whole only accessible through the root, I would like to be able to list all revisions for the whole aggregate by doing something like auditReader.getRevisions(Root.class, id);

So would it be possible to force envers to include the root (that has been locked) in the revision along with the children entities that have been modified?

The workaround I have found so far is to manually update some dummy property on the root when any child entity is modified.

Environment

None

Activity

Show:
Chris Cranford
July 7, 2017, 2:56 PM

I had hoped we could easily solve this by overriding the default setting for org.hibernate.envers.do_not_audit_optimistic_locking_field to false and Envers would see that the parent entity was modified (via the version attribute) and audit the row; however that isn't the case since ORM handles the OPTIMISTIC_FORCE_INCREMENT as a before transaction completion task.

I need to investigate if we could look into plugging into the LockEventListener and based on the proposed LockEvent state, make a decision about whether or not we need to perform any activity on an entity. The tricky part is obtaining the necessary entity state to generate the audit row.

The following is mainly for my benefit, but the LockEventListener basically registers a BeforeTransactionCompletion callback which is where the actual version will be incremented at the end of the transaction. We need to determine if there is any scenario where the Envers BeforeTransactionCompletion callback fires before this ORM one. If it does, we will need to get creative on how we can determine the old/new version values for the audit row. If it does not, it could be as simple as cache the current version during the LockEventListener and then get the new version when processing the AuditProcess entries and generate an audit row.

I believe the caveat here would be to only do this under a specific use case:

1. Optimistic locking field is audited, e.g. org.hibernate.envers.do_not_audit_optimistic_locking_field=false.
2. The only change to the entity was the optimistic locking field, no actual entity attributes were modified. If attributes were modified, the normal PostUpdateEvent callbacks would handle this use case and therefore audit the row without any special logic.

Thoughts?

Jimi Rønberg
March 7, 2019, 8:24 AM

Hi @Chris

To me the use-case sounds correct.

Could you prioritize this issue ?

Best regards

Jimi

Jimi Rønberg
March 7, 2019, 10:14 AM

Could this be part of release 5.4.2 ?

Chris Cranford
March 7, 2019, 2:19 PM
Edited

, I will take a look and see; although I can't promise anything.

Assignee

Chris Cranford

Reporter

Xavier Dury

Fix versions

Labels

None

backPortable

None

Suitable for new contributors

None

Requires Release Note

None

Pull Request

None

backportDecision

None

Components

Priority

Minor
Configure