如何检查Hibernate中的实体是否脏了?

时间:2013-12-05 06:28:01

标签: java hibernate jpa orm jpa-2.0

如何检查Hibernate中的实体是否处于脏状态?即我希望只有在某些字段发生变化时才设置UpdatedByUpdatedAt。所以我可以手动对比检查2个对象中的每个字段,但是可能存在一些更优雅的方法吗?

另外,如果我将对象的字段设置为与之前相同的值,那么hibernate是否会使实体dirty生效?即:

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

修改

但是我还有另一个问题 - 我有嵌套集合的实体,所以如果只改变了该集合中的元素,那么我想只在该集合元素上设置UpdatedBy,而不是在拥有该集合的对象上。我使用级联操作进行更新。

3 个答案:

答案 0 :(得分:8)

是一个优秀的问题,这是简短的回答:Hibernate-Session有一个方法isDirty()

示例的长答案(测试案例1):

如果你在Hibernate之上使用Seam / POJOs / JPA。 你想在调用entityManager.flush()之前知道哪些实体是脏的 - 即知道Hibernate将发出更新语句的实体 - 并对这些记录应用一些更改(设置一些值,如谁更改了记录等)

你知道Hibernate-Session有一个方法isDirty(),但在某些情况下这还不够。

你可以在你的persistence.xml文件中注册一个Hibernate-Interceptor

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

并拦截方法onFlushDirty(...)并将脏对象保存在地图中但是如何在以后访问此地图?我没有在运行时访问拦截器(所以我可以调用interceptor.getDirtyEntities()),你有这个:

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);  
     }  
...  
}  

解决此测试案例: 如果只需要更新那些实体,则无需知道哪些实体发生了更改。您可以在@PreUpdate方法中添加代码(填充更改它们的用户)。脏的实体将被相应地修改,那些不会被调用此方法的实体因为没有更新(并且Hibernate将检测到它)。您可以对@PrePersist方法中的新实体执行相同操作,该方法可能完全相同。您可以使用两者注释相同的方法。

如果您还需要记录哪些字段已被更改,我建议先查看Envers。

答案 1 :(得分:0)

onFlushDirty(...)方法可以帮我检查脏集合。具有嵌套集合的父实体被传递到onFlushDirty,但我不知道传入的实体可能是集合元素。一旦我发现它,它既适用于嵌套集合又适用于其父实体。

public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types)

另一个方法onCollectionUpdate(...)也可用于捕获脏集合,它在onFlushDirty(...)之后调用。

答案 2 :(得分:-3)

为什么要延长你的生命?我建议只是检测实体

getEntityManager().detach(myEntity)

从DB查找其持久化表示,然后您可以自行决定 如果相关字段确实发生了变化,那么您可以创建新版本。 至少要确保这个对象是脏的:)