我在一個簡單的 Spring Boot 應用程式中遇到了一個奇怪的問題,我在其中更新了父物體,洗掉了它的所有子物體,然后創建了新物體。
保存后,生成的物體看起來很好,并且有所有新的子物體,但是當我再次查詢它時,我發現其中一個子物體丟失了!
快速而骯臟的解決方案是將代碼拆分為兩個事務,但我想了解孤兒洗掉行為的原因。
這是服務代碼:
@Service
public class ParentService {
private final EntityManager em;
public ParentEntity getParent(UUID parentId) {
return em.createQuery(
"SELECT p "
"from ParentEntity p "
"JOIN FETCH p.children "
"WHERE p.id = :parentId", ParentEntity.class)
.setParameter("parentId", parentId)
.getSingleResult();
}
@Transactional
public ParentEntity resetChildren(UUID parentId) {
var parent = getParent(parentId);
parent.getChildren().clear();
addChildren(parent, 2);
em.persist(parent);
return parent;
}
private void addChildren(ParentEntity parent, int childCount) {
for (var i = 0; i < childCount; i ) {
parent.addChildren(new ChildEntity());
}
}
}
重置子級并再次獲取父級后的 SQL 輸出是這樣的:
select parententi0_.id as id1_1_0_, children1_.parent_id as parent_i2_0_1_, children1_.id as id1_0_1_, children1_.id as id1_0_2_, children1_.parent_id as parent_i2_0_2_ from parent parententi0_ left outer join child children1_ on parententi0_.id=children1_.parent_id where parententi0_.id=?
insert into child (parent_id, id) values (?, ?)
insert into child (parent_id, id) values (?, ?)
delete from child where id=?
delete from child where id=?
delete from child where id=? <-- One extra delete
select parententi0_.id as id1_1_0_, children1_.parent_id as parent_i2_0_1_, children1_.id as id1_0_1_, children1_.id as id1_0_2_, children1_.parent_id as parent_i2_0_2_ from parent parententi0_ left outer join child children1_ on parententi0_.id=children1_.parent_id where parententi0_.id=?
物體如下所示:
父母
@Entity
@Table(name = "parent")
public class ParentEntity {
@Id
@GeneratedValue
private UUID id;
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<ChildEntity> children = new HashSet<>();
...
public void addChildren(ChildEntity child) {
this.children.add(child);
child.setParent(this);
}
...
}
還有孩子
@Entity
@Table(name = "child")
public class ChildEntity {
@Id
@GeneratedValue
private UUID id;
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "parent_id")
private ParentEntity parent;
...
}
對此有一個重要說明,在我的用例中,這些物體的 id 是 UUID。我無法使用任何數字 ID
可以在此處找到帶有單元測驗的代碼存盤庫
發生了一件有趣的事情,如果我決定添加 1 個孩子,而不是兩個或更多,那么父母本身就會被洗掉!因此,感覺就像我正在查看 Hibernate 中的錯誤。
uj5u.com熱心網友回復:
問題是我在孩子方面有級聯,這導致了非常非常奇怪的結果。我不想在級聯時洗掉父級,所以我不需要。
解決方法是將孩子更改為:
@Entity
@Table(name = "child")
public class ChildEntity {
@Id
@GeneratedValue
private UUID id;
@ManyToOne // <---- No more cascade!
@JoinColumn(name = "parent_id")
private ParentEntity parent;
...
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/435699.html
上一篇:JavaJPA只寫嵌套物體的ID
下一篇:Gradle掃描而不傳輸資訊?
