I'm trying to add auditing functionality to my entities, using an embedded entity and EntityListeners for updating the audit fields on prePersist and preUpdate.

It works except when an entity is updated and a flush is performed on the EntityManager:
- The @PreUpdate listener is invoked and changes the values
- But DatabaseQueryMechanism.updateObjectForWriteWithChangeSet() does ignore any @PreUpdate changes if it's executed within a EntityManager.flush().

Has anybody had similar problems? Is there a workaround? I'm trying to avoid committing and re-opening a new transaction.

I experienced something similar, which had to do with the fact that these events are called when the object itself is being processed. This can mean that other related objects already where inserted/updated and that changes made to those objects simply are ignored. The events are not fired "en masse" before the actual persisting starts, but during the process. Maybe this is related.

Thomas wrote:
> Hello all,
>
> I'm trying to add auditing functionality to my entities, using an
> embedded entity and EntityListeners for updating the audit fields on
> prePersist and preUpdate.
>
> It works except when an entity is updated and a flush is performed on
> the EntityManager:
> - The @PreUpdate listener is invoked and changes the values
> - But DatabaseQueryMechanism.updateObjectForWriteWithChangeSet() does
> ignore any @PreUpdate changes if it's executed within a
> EntityManager.flush().
>
> Has anybody had similar problems? Is there a workaround? I'm trying to
> avoid committing and re-opening a new transaction.
>
> I'm experiencing this problem in EclipseLink v1.1.2, 1.1.3 and 1.2.0.
>
> Thanks
> Thomas

I've tracked down the problem where the flush explicitly ignores changes by any events that happened to updated entities (DatabaseQueryMechanism.updateObjectForWriteWithChangeSet(), line 1080 in if uowChangeSet.isChangeSetFromOutsideUOW()) - for some reason it is working when the entities are newly persisted.

After isolating the problem in a small testcase I found the Hibernate does not have this problem.

I decided to use an application level event; so before committing I made sure that my application called the logic that normally would be in the @PreUpdate. ATM I could also let my ExtendedEntityManager generate such an event.

Tom

Thomas wrote:
> Were you able to solve this problem?
>
> I've tracked down the problem where the flush explicitly ignores changes
> by any events that happened to updated entities
> (DatabaseQueryMechanism.updateObjectForWriteWithChangeSet(), line 1080
> in if uowChangeSet.isChangeSetFromOutsideUOW()) - for some reason it is
> working when the entities are newly persisted.
>
> After isolating the problem in a small testcase I found the Hibernate
> does not have this problem.
>
> Cheers
> Thomas

In order to raise the preUpdate events, the object's changes must be computed, if you then change the object again in this event, then new changes will not be picked up (as this would require us re-computing the changes again, which would be twice as much work, but might be a useful option to have).

You can use the DescriptorEvent preUpdate instead of the JPA event, this will give you access to the DescriptorEvent object, which has an API, updateAttributeWithObject(), which will update the object, row and change set.

James,
thanks for that. I was trying to avoid any provider specific API and isn't JPA's preUpdate event intended to give an EntityListener the chance to modify the updated objects? Mind you, that it all works fine if you don't do a flush() and end the transaction normally. So I think it's a bug with EclipseLink's flush.

James,
thanks for that. I was trying to avoid any provider specific API and isn't JPA's preUpdate event intended to give an EntityListener the chance to modify the updated objects? Mind you, that it all works fine if you don't do a flush() and end the transaction normally. So I think it's a bug with EclipseLink's flush.