休止状態で 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 は、挿入前または更新前にこの検証を呼び出します。ただし、バリデーターがデータベースからレコードをフェッチしようとすると、休止状態がセッションをフラッシュします。検証が実行されるドメイン オブジェクトが完全に焼き付けられていない (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 に変更する必要がありますか? 実際のエンティティとは異なる、新しいセッションまたは永続的なコンテキストを取得することは可能ですか? 休止状態とともに春の mvc を使用しています。
編集
source.getPersistenceContext().getEntityEntries() には、現在検証中のエンティティがあることがわかりました。挿入する前にここに存在する必要がありますか?