strange behavior of collection property mod columns

Description

This will create this audit record:

id

REV

REVTYPE

REVEND

REVEND_TSTMP

value

value_MOD

embeddables_MOD

1

1

0

NULL

NULL

a

1

1

However, if we update the entity after persist it. for example:

this will create this audit record:

id

REV

REVTYPE

REVEND

REVEND_TSTMP

value

value_MOD

embeddables_MOD

1

1

0

NULL

NULL

b

1

0

The value of column 'embeddables_MOD' changed from 1 to 0, though embeddables is not updated at all.

Environment

java 8, wildfly 10.1.0.Final

Activity

Show:
Chris Cranford
July 25, 2018, 2:55 PM

If she does end up doing the backport, she'll do that against HHH-11582. I'm going to close this as its fixed by the other JIRA.

Xj Chen
July 26, 2018, 4:17 AM

Data integrity is very important. Although I haven't thought of the impact of this issue for the time being, this issue does produce some data that is incompatible with subsequent versions, which is very bad.

Chris Cranford
July 26, 2018, 1:49 PM

While I may be splitting semantics here, I just want to be clear that the data previously generated prior to the fix in is not incompatible.

The problem boils down to the fact that prior to HHH-11582, queries that used the hasChanged() predicate would return incorrect results if you persisted and then updated the same entity within the same transaction. This scenario is very dependent on your persistence code in your application so its hard to really gauge the overall impact to users this had. The data after the fix obviously makes queries that utilize hasChanged() work across all persistence operations regardless if they occur within the same or across multiple transactions.

That said, a general rule here is that when REVTYPE = 0 and the column is not null or collection is not empty, the associated _MOD field should be TRUE / 1. It should be trivial to write a small migration application that looks at revisions of audited entities, compares the state between 2 revisions and uses JDBC to update the appropriate fields should you desire consistency with rows generated prior to HHH-11582. Honestly, it's things like this which I'd like to spend time doing some R&D on to try and devise a way that perhaps Envers could do some of this for users, but often times there are so many variables at play that may not always be possible.

The only use case that the above wouldn't be able to differentiate would be empty collections versus null collections; however from a real technical perspective, would could argue that the collection wasn't modified even if it was initialized as not-null. So leaving those column values as FALSE / 0 for rows prior to versus them being TRUE / 1 afterward really don't impact the end result imo.

Xj Chen
July 31, 2018, 5:38 AM

@Chris Cranford Recently I am doing work on implementing auditing functions at the native database level. Although the application layer is done by Envers, we still need to ensure the integrity of the audit table data when our dba deal with the database. And there is little infomation about this in the document. I really can't understand how the audit table corresponding to the ElementCollection property works. According to the test, when I modify a piece of data in the ElementCollection property, the corresponding audit table inserts a record that represent inserting a new entry first, and then inserts a record that represent deleting the original entry. But the REVEND of the record that represent deleting the entry record is always null.

Chris Cranford
July 31, 2018, 2:03 PM

, I'll answer your initial question here but should you have further ones, I'd suggest we have those conversations on the forums or HipChat as they'll not pollute this jira with unrelated discussions and we avoid pinging watchers and such on closed topics.

When using the ValidityAuditStrategy and a record is updated or deleted, the original audit row insert will always set REVEND to null as well as the optionally enabled REVEND_TSTMP field. That particular strategy deals with setting those values in subsequent update statements.

So for example, in a transaction where I remove an element from the element-collection (I persisted in a separate transaction for clarity):

The key here is the last two operations in this transaction where the UPDATE statements are executed. The first deals with updating the special columns in the element-collection by locating the proper record and setting the 2 column values accordingly. Once the child records have been modified, we lastly update the root entity table.

In a situation where an entity participates in certain inheritance strategies, you may have several entity tables that will be updated to make sure that the two columns are synchronized to support proper partitioning of the table data across that type of table relationship.

Assignee

Chris Cranford

Reporter

Xj Chen

Fix versions

None

Labels

backPortable

Backport?

Suitable for new contributors

None

Requires Release Note

None

Pull Request

None

backportDecision

None

Worked in

5.1.12

Components

Affects versions

Priority

Major
Configure