2

I've got two lists of entities: One that is the current state of the rows in the DB, the other is the changes that were made to the list. How do I audit the rows that were deleted, added, and the changes made to the entities? My audit table is used by all the entities.

Entity listeners and Callback methods look like a perfect fit, until you notice the sentence that says: A callback method must not invoke EntityManager or Query methods! Because of this restriction, I can collect audits, but I can't persist them to the database :(

My solution has been a complex algorithm to discover the audits.

If the entity is in the change list and has no key, it's an add

If the entity is in the db but not the changes list, it's a delete

If the entity is in both list, recursively compare their fields to find differences to audit (if any)

I collect these and insert them into the DB in the same transaction I merge the changes list. But I hate the fact that I'm writing this by hand. It seems like JPA should be able to do this logic for me.

One solution we've come up with is to use an Entity Listener that posts the audits to a JMS queue. The queue then inserts the audits into the database. But I don't like this solution because I think setting up a JMS queue is a pain. It's currently the best solution we've got though.


I'm using eclipselink (ideally, that's not relevant) and have found these two things that look helpful but the JMS queue is a better solution than them:

Daniel Kaplan
  • 62,768
  • 50
  • 234
  • 356

1 Answers1

0

The EntityListener looks like a good approach since you are able to collect the audit information.

Have you tried persisting the information in a different transaction than the one persisting the changes? perhaps obtaining a reference to a Stateless EJB (assuming you are using EJBs) and using methods marked with @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW). In this way the transaction persisting the original changes is put on hold while the transaction of the audit completes. Note that you will not be able to access the updated information in this separate audit transaction, since the original one has not committed yet.

German
  • 3,560
  • 7
  • 32
  • 34
  • If I put it in a REQUIRES_NEW it'll still be using the entity manager which is what it says is forbidden. – Daniel Kaplan May 10 '13 at 22:18
  • You will be using a different instance of an EntityManager in another transaction, which creates a different persistence context than the one where the changes are living. I'm not sure if the note is because of some kind of problem in the current persistence context or if it forbids any kind of database interaction. – German May 10 '13 at 22:25