Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check if entity in Hibernate is dirty?

How to check if entity in Hibernate is in dirty state? I.e. I want do set UpdatedBy and UpdatedAt only if some field has changed. So I can do object check manually comparing each field in 2 objects, but may be there exist some more elegant way to do it?

Also, does hibernate makes entity dirty if I set to object's field same value as it was before? I.e.:

String name = myEntity.getName()
myEntity.setName(name);

EDIT:

But also I have another problem - I have entity with nested collections, so if has changed only element in that collection, then I want to set UpdatedBy only on that collection element, but not on object that owns this collection. I make updates using cascade operations.

like image 978
WelcomeTo Avatar asked Sep 07 '25 10:09

WelcomeTo


1 Answers

This is an excellent, question, this is the short answer: Hibernate-Session has a method isDirty().

Long Answer with Example (TEST CASE 1):

If your are using Seam/POJOs/JPA on top of Hibernate, you would like to know which entities are dirty before calling entityManager.flush() - i.e. know for which entities Hibernate would issue an update-statement - and apply some changes on these records (set some values like who changed the record and so on).

You know that the Hibernate-Session has a method isDirty(), but this is not enough in some case.

You could register a Hibernate-Interceptor in you persistence.xml-file:

         <property name="hibernate.ejb.interceptor" value="path.to.MyInterceptor" />  

and intercept the method onFlushDirty(...) and save the dirty objects in a map but how can I access this map later on? I don't have access to the interceptor at runtime (so that I could call interceptor.getDirtyEntities()), you have this:

public class MyInterceptor extends EmptyInterceptor {  
         private Map<IdentityKey,Object> dirtyEntitiesMap = new HashMap<IdentityKey,Object>();  
  
     @Override  
     public boolean onFlushDirty(Object entity, Serializable id,  
               Object[] currentState, Object[] previousState,  
               String[] propertyNames, Type[] types) {  
  
           dirtyEntitiesMap.put(new IdentityKey(id, entity.getClass()), entity);    
           return super.onFlushDirty(entity, id, currentState, previousState, propertyNames, types);  
     }  
...  
}  

SOLVER THIS TEST CASE: 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.

like image 95
tomj0101 Avatar answered Sep 09 '25 05:09

tomj0101