2012-06-11 59 views
0

我的域模型:支付和帳戶之間的單向多對一映射。當另一個被管實體持有對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一起。

回答

0

通過讀取支付對象,它變得可管理。當您刪除賬戶並致電提交時,JPA提供商會從受管理的付款中找到引用相同的確切賬戶對象,並且因爲關係標記爲級聯持續存在,所以必須堅持該賬戶。所以淨效應是取消你的刪除嘗試。

JPA需要維護關係,以便您的對象模型反映出您希望數據庫的外觀。在這種情況下,您必須先從支付中移除帳戶參考,然後才能將其刪除,或在同一交易中刪除支付。

+0

Thx!然而jpa2規範仍然令我困惑。你的解釋與第3.2.2節中的最後一個要點相符。但是,我不清楚爲什麼堅持要求被引用的帳戶。我確實指定了cascade = PERSIST,但我發現它很奇怪爲什麼持久操作被級聯到Account,因爲我沒有調用Payment上的持久操作。 –

+0

問題解決。 flush()操作將persist()操作應用於Account。規範指出:應用於實體X的flush操作的語義如下:如果X是一個託管實體,它將與數據庫同步。對於通過X關係引用的所有實體Y,如果與Y的關係已使用級聯元素值cascade = PERSIST或cascade = ALL進行註釋,則將持久操作應用於Y.希望這有助於某人。 –

相關問題