質問のリンクからポスターが中断したところを拾い上げると、どうやって再接続したかのおおよその/関連するコードがここにあります。その下に、何が起こっているかの概要があります。
@Repository
public abstract class DaoHibernate<T> implements Dao<T> {
@Override
public T reattach(T entity) {
if (getCurrentSession().contains(entity)) {
return entity;
}
if (entity instanceof User) {
return (T) reattachedUser((User) entity);
}
if (entity instanceof Content) {
Content content = (Content) entity;
User user = content.getUser();
if (!currentSession().contains(user)) {
content.setUser(reattachedUser(user));
}
content.setAttributes(persistentAttributesMap(content.getId(), content.getAttributes(), Content.class);
getCurrentSession().lock(content, LockMode.NONE);
return entity;
}
throw new UnsupportedOperationException("reattach is not supported for entity: " + entity.getClass().getName());
}
private User reattachedUser(User user) {
user.setAttributes(persistentAttributesMap(user.getId(), user.getAttributes(), User.class));
getCurrentSession().lock(user, LockMode.NONE);
return user;
}
@SuppressWarnings ("unchecked")
private Map<String, String> persistentAttributesMap(long id, Map<String, String> attributes, Class clazz) {
SessionFactory sessionFactory = getSessionFactory();
Session currentSession = sessionFactory.getCurrentSession();
String role = clazz.getName() + ".attributes";
CollectionPersister collectionPersister = ((SessionFactoryImplementor) sessionFactory).getCollectionPersister(role);
MapType mapType = (MapType) collectionPersister.getCollectionType();
PersistentMap persistentMap = (PersistentMap) mapType.wrap((SessionImplementor) currentSession, attributes);
persistentMap.setOwner(id);
persistentMap.setSnapshot(id, role, ImmutableMap.copyOf(attributes));
persistentMap.setCurrentSession(null);
return persistentMap;
}
...
}
ウォークスルー
ご覧のとおり、現在のセッションに既に存在するエンティティを再アタッチしないようにする必要があります。再アタッチしないと、hibernate が例外をスローします。そのため、 で行う必要getCurrentSession().contains(entity)
がありreattach()
ます。contains()
hibernate はentity.hachCode()
エンティティのルックアップに を使用せず、 を使用することに注意してくださいSystem.identityHashCode(entity)
。これにより、同等のインスタンスであるだけでなく、セッションに既に存在する可能性のあるまったく同じインスタンスが保証されます。つまり、インスタンスの再利用を適切に管理する必要があります。
関連付けられたエンティティが でマークされている限りCascade.ALL
、休止状態は正しいことを行うはずです。つまり@ElementCollection
、属性のマップのような休止状態で管理されたコレクションがない限りです。この場合、PersistentCollection
( PersistentMap
、正確には ) を手動で作成し、 のように適切なプロパティを設定するpersistentAttributesMap
必要があります。そうしないと、hibernate が例外をスローします。つまり、 では、次のPersistentMap
ことを行う必要があります。
- 所有者とスナップショット キーを所有エンティティの ID として設定します。
- hibernate が認識するように、完全修飾された entity.property 名としてスナップショット ロールを設定します。
- スナップショット
Serializable
引数を既存のコレクションの不変のコピーとして設定します
- セッションを設定して
null
、休止状態が既存のセッションに 2 回アタッチしようとしていると認識しないようにします。
再接続を完了するには、 を呼び出しますsession.lock(entity, LockMode.NONE)
。この時点で、私のテストからわかる限り、休止状態はこのエンティティを尊重し、 を呼び出すとすべての変更を正しく保持しますsaveOrUpdate()
。
注意事項
これは、すべてのケースに対する一般的な解決策ではないことを認識しています。これは、他の人がうまく利用して改善できる、私の特定の問題に対する簡単な解決策にすぎません。ソフトウェアは反復的です。