16

Currently, I'm working on a Java EE project with some non-trivial requirements regarding persistence management. Changes to entities by users first need to be applied to some working copy before being validated, after which they are applied to the "live data". Any changes on that live data also need to have some record of them, to allow auditing.

The entities are managed via JPA, and Hibernate will be used as provider. That is a given, so we don't shy away from Hibernate-specific stuff. For the first requirement, two persistence units are used. One maps the entities to the "live data" tables, the other to the "working copy" tables. For the second requirement, we're going to use Hibernate Envers, a good fit for our use-case.

So far so good. Now, when users view the data on the (web-based) front-end, it would be very useful to be able to indicate which fields were changed in the working copy compared to the live data. A different colour would suffice. For this, we need some way of knowing which properties were altered. My question is, what would be a good way to go about this?

Using the JavaBeans API, a PropertyChangeListener could suffice to be notified of any changes in an entity of the working copy and keep a set of them. But the set would also need to be persisted, since the application could be restarted and changes can be long-lived before they're validated and applied to the live data. And applying the changes on the live data to obtain the working copy every time it is needed isn't feasible (hence the two persistence units). We could also compare the working copy to the live data and find fields that are different. Some introspection and reflection code would suffice, but again that seems rather processing-intensive, not to mention the live data would need to be fetched. Maybe I'm missing something simple, or someone know of a wonderful JPA/Hibernate feature I can use. Even if I can't avoid making (a) separate database table(s) for storing such information until it is applied to the live data, some best-practices or real-life experience with this scenario could be very useful.

I realize it's a semi-open question but surely other people must have encountered a requirement like this. Any good suggestion is appreciated, and any pointer to a ready-made solution would be a good candidate as accepted answer.

G_H
  • 11,739
  • 3
  • 38
  • 82
  • Have you tried hibernate-envers ? – Xavier Dury Feb 16 '16 at 07:46
  • @XavierDury It is explicitly mentioned in the post that we use Envers for keeping a history of changes. What I'm looking for is a live way of knowing which properties were changed in a particular entity, so we can show that to the user, without the huge overhead of having to compare two versions of the entity every time they're shown. – G_H Feb 16 '16 at 08:05
  • 1
    @G_H just for my knowing: is it really that bad to load two versions of the same entity to compare it's values? I mean, is there anything 'special' about these entities? I don't see it becoming a performance problem if you always keep your persistence layer as lean as possible. – Bonifacio Feb 16 '16 at 11:05
  • Do you really want to deal with it in persistence tier? To me it's much more the responsibility of the UI tier. Java EE's MVC framework JSF for example has `ValueChangeListener` interface for the purpose. – BalusC Feb 16 '16 at 11:27
  • @Bonifacio It might not be a huge problem... But it would definitely have some performance impact. Not just loading the entities, but detecting the differences too. I was wondering if there'd be a neat method that someone has successfully tried. – G_H Feb 16 '16 at 11:48
  • @BalusC You are absolutely right. However, the front-end is .NET and exchanges data with the back-end via DTOs. I have no influence over this design. – G_H Feb 16 '16 at 11:50
  • In JPA side you could use entity listeners, but you still have to delegate/push it to the front end in some way (if it were Java EE, I'd use CDI events). After all, this is convoluted and most likely exactly the other way round from what you seem to intend (notifying users about changes done by other users versus tracking changes made by user itself). It's much better/easier to take care of it in the front end specific MVC framework as it's exactly the one who has both the original model and the changed value directly at hands. – BalusC Feb 16 '16 at 12:04
  • @BalusC Well, not exactly... Basically changes are made on some "working copy", which is also persisted. The application might have been restarted, a user would come back to some page and the data shown is the working copy. In fact, it always is; they're kept at any time and changes are only propagated to the "live data" after some sort of validation. So it's a matter of, "what has changed in this JPA entity since it was copied from the live data". The two ways I can think of is a comparison with the live data entities, or persisting some list of changed properties separately. – G_H Feb 16 '16 at 12:10
  • 2
    Ah, completely missed the part "working copy is also persisted". It's now clearer. Forget about entity listeners and all, this is different. You basically need a "javabean diff", for which indeed libraries exist (try that keyword in search). Never tried myself though, so I can't speak from experience. – BalusC Feb 16 '16 at 12:12
  • 1
    This looks to me a bit like an application for [CQRS](http://martinfowler.com/bliki/CQRS.html) and an [EventStore](https://geteventstore.com). – Steve C Feb 17 '16 at 11:12
  • What about a change tracking feature of your database if available? Another idea is to manually track any change in a changelog (like a database transaction log) in the file system or in a separate generic table. However, this is a redundant information (applying changelog to working copy yields live data) which must keep in sync. I wonder if you get a performance benefit here. The next idea is to store a "change bit mask" with each working copy where a bit per column is set when there is a change between both versions. If mask is 0: no diff, otherwise you know which columns are different. – Claude Mar 17 '16 at 07:34

1 Answers1

0

Maybe you can use the Hibernate flush entity event listener. The dirty properties are calculated before the flush. You can store them somewhere in your database.

A sample code of using the dirty properties feature of Hibernate which may give you an idea.

S.Stavreva
  • 577
  • 4
  • 8
  • In the end we've not really needed this (yet) and simply present the user with the "working copy". If at some point that which was changed needs to be explicitly marked, the flush listener would probably be the best approach, so I'm marking this as accepted. I reckon class org.hibernate.EmptyListener could provide a base for finding the dirty properties. Your link has 404'd, so maybe it would be better to replace it with some SO questions/answers providing info on how to customize dirty property handling. – G_H Feb 15 '17 at 09:48