我在休眠中使用 JSR-303 验证。我创建了一个自定义验证器注释,它通过查询数据库来检查数据完整性。
例如:
public boolean isValid(Object value, ConstraintValidatorContext context) {
if(value == null){
return true;
}
//This method uses entityManager to fetch a list from database
Map<String, String> pickList = pickListProvider.getPickList(picklistName);
return pickList.contains(value);
}
用法:
public class UserProfile extends Persistent {
//Member fields come here
@PicklistConstraint(name="languages")
private String prefLanguage;
}
这里的 UserProfile 是一个使用 Hibernate 持久化的实体。Hibernate 在预插入或预更新时调用此验证。但是,当验证器尝试从数据库中获取记录时,hibernate 正在刷新会话。由于运行验证的域对象没有完全烘焙(没有 Id 字段),我得到以下异常
org.hibernate.AssertionFailure: null id in <domain object here> entry (don't flush the Session after an exception occurs)
at org.hibernate.event.internal.DefaultFlushEntityEventListener.checkId(DefaultFlushEntityEventListener.java:79)
at org.hibernate.event.internal.DefaultFlushEntityEventListener.getValues(DefaultFlushEntityEventListener.java:194)
at org.hibernate.event.internal.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:156)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:225)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:99)
at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:58)
at org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1186)
at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1241)
at org.hibernate.internal.QueryImpl.list(QueryImpl.java:101)
at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:257)
经过调查,我发现 DefaultAutoFlushEventListener 的 flushMightBeNeeded 返回 true:
private boolean flushMightBeNeeded(final EventSource source) {
return !source.getFlushMode().lessThan(FlushMode.AUTO) &&
source.getDontFlushFromFind() == 0 &&
( source.getPersistenceContext().getEntityEntries().size() > 0 ||
source.getPersistenceContext().getCollectionEntries().size() > 0 );
}
问题是 FlushMode 是 AUTO 并且 source.getPersistenceContext().getEntityEntries().size() 有一些条目。在这种情况下我应该采取什么方法?我应该将 FlushMode 从 AUTO 更改为 MANUAL 吗?是否可以获得与实际实体不同的新会话或持久上下文?我正在使用spring mvc和hibernate。
编辑
我发现 source.getPersistenceContext().getEntityEntries() 具有当前正在验证的实体。在插入之前应该出现在这里吗?