我的域模型:支付和帳戶之間的單向多對一映射。當另一個被管實體持有對CascadeType.PERSIST的引用時,未觸發實體的移除
@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;
}
});
}
這導致DataIntegrityViolationException作爲被髮起交易之後執行的SQL提交,是:
- 從刪除BankAccount其中ID =?
- 從賬戶ID =?刪除和版本=?
現在我有一個奇怪的「功能」,當我
- 變化增加級聯的多對一映射(尤其是ALL或PERSIST)
- 並更改測試域讀取創建付款在同一事務中
更具體地去除所述帳戶時:
@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;
}
});
}
這不會導致DataIntegrityViolationException,因爲在啓動事務提交後沒有執行SQL。
任何想法是什麼導致這種行爲? PERSIST在尋找付款或移除賬戶時有什麼作用?這可能是實施JPA標準中的一個錯誤嗎?順便說一句,我使用JPA2和Hibernate 4.1.3.Final一起。
Thx!然而jpa2規範仍然令我困惑。你的解釋與第3.2.2節中的最後一個要點相符。但是,我不清楚爲什麼堅持要求被引用的帳戶。我確實指定了cascade = PERSIST,但我發現它很奇怪爲什麼持久操作被級聯到Account,因爲我沒有調用Payment上的持久操作。 –
問題解決。 flush()操作將persist()操作應用於Account。規範指出:應用於實體X的flush操作的語義如下:如果X是一個託管實體,它將與數據庫同步。對於通過X關係引用的所有實體Y,如果與Y的關係已使用級聯元素值cascade = PERSIST或cascade = ALL進行註釋,則將持久操作應用於Y.希望這有助於某人。 –