私のドメイン モデル: 支払いとアカウントの間の一方向多対 1 マッピング。
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "ACCOUNT_TYPE")
public abstract class Account { … }
@Entity
@DiscriminatorValue(Account.Constants.BANK_ACCOUNT)
public class BankAccount extends Account { … }
@Entity
public class Payment {
@ManyToOne
private Account receiver;
...
}
私のテストケース(AbstractJUnit4SpringContextTestsを拡張する):
@Test(expected=DataIntegrityViolationException.class)
public void deleteAccountReferencedByPayment() {
createPayment();
getTransactionTemplate().execute(new TransactionCallback<Object>() {
@Override
public Object doInTransaction(TransactionStatus status) {
Account receiver = accountRepository.findAllByEmail(email1).get(0);
accountRepository.remove(receiver);
return null;
}
});
}
トランザクションのコミットを開始した後に実行される SQL は次のとおりであるため、これにより DataIntegrityViolationException が発生します。
- ID=? の BankAccount から削除します。
- ID=? のアカウントから削除 バージョン=?
今、私は奇妙な「機能」を持っています
- ドメインを変更して、ManyToOne マッピング (特に ALL または PERSIST) にカスケードを追加します。
- AND アカウントを削除するときに、同じトランザクションで作成された支払いを読み取るようにテストを変更します
すなわち:
@Entity
public class Payment {
@ManyToOne(cascade = {CascadeType.PERSIST})
private Account receiver;
...
}
@Test(expected=DataIntegrityViolationException.class)
public void deleteAccountReferencedByPaymentStrangeBehaviour() {
final Long paymentId = createPayment();
getTransactionTemplate().execute(new TransactionCallback<Object>() {
@Override
public Object doInTransaction(TransactionStatus status) {
paymentRepository.find(paymentId);
Account receiver = accountRepository.findAllByEmail(email1).get(0);
accountRepository.remove(receiver);
return null;
}
});
}
トランザクション コミットの開始後に SQL が実行されないため、DataIntegrityViolationException は発生しません。
この動作の原因は何ですか? PERSIST は、支払いの検索やアカウントの削除とどのような関係がありますか? これは、JPA 標準の実装におけるバグでしょうか? ところで、私は Hibernate 4.1.3.Final と一緒に JPA2 を使用しています。