[英]Hibernate update before insert in one to many
由於 Hibernate 執行的操作順序,我得到了約束違反異常。 我定義了以下實體。
@Entity
public class A {
@Id
private Integer id;
@OneToMany(mappedBy = "a", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private List<B> bList;
public void setBList(List<B> bList) {
if(CollectionUtils.isNotEmpty(this.bList)) {
this.bList.clear();
}
if(CollectionUtils.isNotEmpty(bList)) {
this.bList.addAll(bList);
}
}
}
@Entity
@Table(uniqueConstraints={@UniqueConstraint(columnNames = {"name", "a_id", "isDeleted"})})
public class B {
@Id
private Integer id;
private String name;
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name="a_id")
private A a;
private boolean isDeleted;
}
當我在實體 A 中設置新的 B 列表(包含一個更新為已刪除的項目和一個在與約束對應的列中具有相同值的新項目)並保存實體 A 時,我得到約束違規。
Hibernate 在將舊項目更新為已刪除之前執行新項目的插入,導致違反約束,而實際上應用程序中的數據是正確的。
我在這里做錯了什么還是對此有任何配置或修復?
由於 OP 的評論指出它沒有抓住重點,答案在 2021 年 5 月 7 日更改
有兩件事你應該改變才能正常工作
您不應該依賴 Hibernate 來為您猜測正確的操作順序。 它依賴於可能不符合您意圖的啟發式方法。 在您的情況下,您應該在軟刪除舊B
之后和持久化新 B 之前調用EntityManager.flush
。
無論如何,當您軟刪除第二個B
時,您的獨特約束會導致問題,這對於唯一列是相同的。 以后更
一般來說,確保 DB 中的這種約束是一個壞主意。 如果您嘗試更新/插入違反它們的實體,那么您將得到一個模糊的PersistenceException
,並且很難警告您的用戶確切原因。 因此,無論如何,您必須在插入/更新之前以編程方式檢查這些約束。 因此,您最好刪除它們並通過您的程序確保唯一性,除非它們對數據完整性至關重要。 不可為空的列和其他純業務邏輯的約束也是如此。
現在來自經驗的最后一條建議:對於軟刪除列,使用TimeStamp
而不是boolean
。 更新和閱讀記錄的工作量相同,但它會為您提供一些有關何時刪除記錄的有價值信息。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.