0

私のドメイン モデル: 支払いとアカウントの間の一方向多対 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 を使用しています。

4

1 に答える 1

0

Paymentオブジェクトを読み込むことにより、管理対象になります。アカウントを削除してcommitを呼び出すと、JPAプロバイダーは、マネージドペイメントから参照されているのとまったく同じアカウントオブジェクトを検出します。関係はカスケード永続化とマークされているため、アカウントを永続化する必要があります。したがって、正味の効果は、削除の試行をキャンセルすることです。

JPAでは、オブジェクトモデルがデータベースの外観を反映するように、関係を維持する必要があります。この場合、アカウント参照を削除する前に支払いから削除するか、同じトランザクションで支払いを削除する必要があります。

于 2012-06-11T17:51:12.330 に答える