如何检查Hibernate中的实体是否处于脏状态?即我希望只有在某些字段发生变化时才设置UpdatedBy
和UpdatedAt
。所以我可以手动对比检查2个对象中的每个字段,但是可能存在一些更优雅的方法吗?
另外,如果我将对象的字段设置为与之前相同的值,那么hibernate是否会使实体dirty
生效?即:
String name = myEntity.getName()
myEntity.setName(name);
修改
但是我还有另一个问题 - 我有嵌套集合的实体,所以如果只改变了该集合中的元素,那么我想只在该集合元素上设置UpdatedBy,而不是在拥有该集合的对象上。我使用级联操作进行更新。
答案 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查找其持久化表示,然后您可以自行决定 如果相关字段确实发生了变化,那么您可以创建新版本。 至少要确保这个对象是脏的:)