JPAでは、このような一括操作を行う場合
update LogEntry e set e.customer = null where e.customer.id = :cid
これによると、同期を壊さないように別のエンティティ マネージャーを使用することをお勧めします: JPA/JPQL での UPDATE SET クエリ
たとえば、EntityManager は、永続コンテキスト内のキャッシュされたエンティティ オブジェクトが UPDATE クエリによって変更されたことを認識していない場合があります。したがって、UPDATE クエリには別の EntityManager を使用することをお勧めします。
休止状態を使用して Wildfly などの JTA 環境で別のエンティティ マネージャーを作成するにはどうすればよいですか? 一括操作用に別の持続性ユニットを作成する必要がありますか?
編集:一括操作に別の PU が必要ない場合、これは新しいトランザクションを使用して解決するのに十分な方法ですか?
@Transactional
public class JpaCustomerRepository implements CustomerRepository {
@Inject
private EntityManager em;
...
@Override
public Customer remove(long id) {
CustomerEntity entity = em.find(CustomerEntity.class, id);
if (entity != null) {
updateLogEntriesToNull(entity);
em.remove(entity);
return entity;
} else {
return null;
}
}
@Transactional(value=TxType.REQUIRES_NEW)
public void updateLogEntriesToNull(CustomerEntity entity) {
em.createNamedQuery(LogEntry.updateCustomerToNull)
.setParameter("cid", entity.getId())
.executeUpdate();
}
...
}
LogEntry.updateCustomerToNullは一括クエリです。
回答:同じクラス内から呼び出されたときにインターセプターが呼び出されないため、これは機能しません。
EDIT2: Andreiからの提案に従って、これはうまくいくはずです:
@Transactional
public class JpaCustomerRepository implements CustomerRepository {
public static class BulkUpdater {
@Inject
private EntityManager em;
@Transactional(value=TxType.REQUIRES_NEW)
public void updateLogEntriesToNull(CustomerEntity entity) {
em.createNamedQuery(LogEntry.updateCustomerToNull)
.setParameter("cid", entity.getId())
.executeUpdate();
}
}
@Inject
private EntityManager em;
@Inject
private BulkUpdater bulkUpdater;
...
@Override
public Customer remove(long id) {
CustomerEntity entity = em.find(CustomerEntity.class, id);
if (entity != null) {
bulkUpdater.updateLogEntriesToNull(entity);
em.remove(entity);
return entity;
} else {
return null;
}
}
...
}
テストでは、インターセプターが 2 回呼び出されることが確認されています。