It depends on your definition of dirty, when I started using ORMs, my definition of dirty was any object that was already registered in the EditingContext (the EOF equivalent of EntitytManager/HibernateSession) but that had information that had not been persisted.
The I learned that for Hibernate, new objects and deleted objects are not
dirty(only modified objects). Since what I wanted was to get a list of the objects that
were going to be saved to the database in the next flush/commitso that I can run validation on them (or just notify the user that there were pending changes) I used interceptors and LifeCycle Callbacks to try and catch all new, modified and to-be-deleted objects... but that made me hit an unbreakable wall: Turns out that if an entity has a
not nullableproperty it can not be registered in the EntitytManager... at first I thought that was a limitation in JPA, but then I decided to try JPA/EclipseLink and discovered this was an Hibernate specific bug, sadly, the Hibernate team is not interested in fixing it.
Oh, and this is a question much more appropriate for the Hibernate Forum... ;-)
Thanks for your reply.
In my case I'm only interested in knowing if my entities loaded from the DB (not newly created ones) where changed by the user.
If I create new ones I already prepopulate certain auditing-attributes so that they are there if the user decides to persist these records.
In case of an update however I can only set these attributes if I know the entity was changed - not otherwise.
So maybe the easier way is to clone all the objects after loading them from DB and compare them before calling flush()?
BTW: I posted the question here because I found some hibernate solutions to this which are not applicable in SEAM, e.g. SessionFactory.buildSession(new MyInterceptor().
You don't need to know which entities changes if you only need to update those. You can add your code (populating the user who changed them) in a @PreUpdate method. The entities which are dirty will be modified accordingly, those that are not will not get this method called since there is nothing to update (and Hibernate will detect that). You can do the same for new entities in a @PrePersist method which is probably identical. You can annotate the same method with both.
If you also need to record which fields have been changed, I'd suggest to look at Envers first.
Jean Luc wrote on Nov 05, 2009 19:20:
You don't need to know which entities changes if you only need to update those. ...
Yes, you are right. That's a good point.
But nontheless I still face a problem: in my @PreUpdate method I would like to fetch one of my components via Component.getInstance(...) in order to set the user who changed the record (I don't know of any other solution to get this value).
I used a project-structure generated by seam-gen, so there is the main-folder and the hot-folder which use different classloaders.
(a) If I insert a @PreUpdate-method in my entity, the entity (in main-folder) does not see my components (in hot-folder) and I get a compiler-error!
(b) If I create a listener and annotate the entity with my listener I get a compile error, too.
Is there a way to get out of this problem?
IIRC, a component does not have to be declared in hot folder. You can create a session-scoped one in the main folder which will store the identity of the user (obtained via @Observer("org.jboss.seam.security.postAuthenticate")). Then in the @PreUpdate method you will have access to this component.
Another way would be through ThreadLocal but the above is simpler.