如何检查休眠中的实体是否脏?

2022-09-01 17:49:28

如何检查休眠中的实体是否处于脏状态?即,我想要设置并且仅当某些字段已更改时才进行设置。所以我可以手动比较2个对象中的每个字段进行对象检查,但是可能存在一些更优雅的方法来做到这一点?UpdatedByUpdatedAt

另外,如果我设置为对象的字段与以前相同的值,休眠是否使实体?即:dirty

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

编辑:

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


答案 1

这是一个很好的问题,这是简短的答案: Hibernate-Session有一种方法 。isDirty()

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

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

您知道休眠会话有一个方法,但在某些情况下这还不够。isDirty()

您可以在持久性.xml文件中注册一个休眠拦截器:

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

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

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


答案 2

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

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

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


推荐