[英]Hibernate Many-to-Many with join-class Cascading issue
我在Foo
和Bar
之間有Many-to-Many
關系。 因為我想獲得有關輔助表的其他信息,所以我必須按照此處的說明創建一個輔助類FooBar
: 使用JPA和Hibernate時,使用額外列映射多對多關聯的最佳方法
我創建了一個Foo,並創建了一些條形圖(保存到DB)。 當我然后使用其中一個條添加到foo
foo.addBar(bar); // adds it bidirectionally
barRepository.save(bar); // JpaRepository
然后創建FooBar的DB條目 - 正如預期的那樣。
但是,當我想再次從foo中刪除相同的欄時,使用
foo.removeBar(bar); // removes it bidirectionally
barRepository.save(bar); // JpaRepository
然后, 不會從數據庫中刪除先前創建的FooBar條目。 通過調試我看到了foo.removeBar(bar);
確實刪除了雙向。 沒有異常被拋出。
難道我做錯了什么? 我很確定它與Cascading選項有關,因為我只保存吧。
我嘗試過的:
在@OneToMany上添加orphanRemoval = true
- 注釋,這些都不起作用。 我認為這是正確的,因為我不刪除 Foo和Bar,只刪除他們的關系。
從@OneToMany注釋中排除CascadeType.REMOVE,但與orphanRemoval相同我認為這不適用於這種情況。
編輯:我懷疑在我的代碼或模型中必須有一些與我的孤兒電影混淆的東西,因為現在已經有2個答案說它有效(使用orphanRemoval=true
)。
最初的問題已得到解答,但如果有人知道什么可能導致我的孤兒無法工作,我會非常感謝您的意見。 謝謝
代碼:Foo,Bar,FooBar
public class Foo {
private Collection<FooBar> fooBars = new HashSet<>();
// constructor omitted for brevity
@OneToMany(cascade = CascadeType.ALL, mappedBy = "foo", fetch = FetchType.EAGER)
public Collection<FooBar> getFooBars() {
return fooBars;
}
public void setFooBars(Collection<FooBar> fooBars) {
this.fooBars = fooBars;
}
// use this to maintain bidirectional integrity
public void addBar(Bar bar) {
FooBar fooBar = new FooBar(bar, this);
fooBars.add(fooBar);
bar.getFooBars().add(fooBar);
}
// use this to maintain bidirectional integrity
public void removeBar(Bar bar){
// I do not want to disclose the code for findFooBarFor(). It works 100%, and is not reloading data from DB
FooBar fooBar = findFooBarFor(bar, this);
fooBars.remove(fooBar);
bar.getFooBars().remove(fooBar);
}
}
public class Bar {
private Collection<FooBar> fooBars = new HashSet<>();
// constructor omitted for brevity
@OneToMany(fetch = FetchType.EAGER, mappedBy = "bar", cascade = CascadeType.ALL)
public Collection<FooBar> getFooBars() {
return fooBars;
}
public void setFooBars(Collection<FooBar> fooBars) {
this.fooBars = fooBars;
}
}
public class FooBar {
private FooBarId id; // embeddable class with foo and bar (only ids)
private Foo foo;
private Bar bar;
// this is why I had to use this helper class (FooBar),
// else I could have made a direct @ManyToMany between Foo and Bar
private Double additionalInformation;
public FooBar(Foo foo, Bar bar){
this.foo = foo;
this.bar = bar;
this.additionalInformation = .... // not important
this.id = new FooBarId(foo.getId(), bar.getId());
}
@EmbeddedId
public FooBarId getId(){
return id;
}
public void setId(FooBarId id){
this.id = id;
}
@ManyToOne
@MapsId("foo")
@JoinColumn(name = "fooid", referencedColumnName = "id")
public Foo getFoo() {
return foo;
}
public void setFoo(Foo foo) {
this.foo = foo;
}
@ManyToOne
@MapsId("bar")
@JoinColumn(name = "barid", referencedColumnName = "id")
public Bar getBar() {
return bar;
}
public void setBar(Bar bar) {
this.bar = bar;
}
// getter, setter for additionalInformation omitted for brevity
}
我從示例代碼中嘗試了這個。 通過幾個'草圖',這再現了錯誤。
事實證明,解決方案就像添加你提到的orphanRemoval = true
一樣簡單。 在Foo.getFooBars()
:
@OneToMany(cascade = CascadeType.ALL, mappedBy = "foo", fetch = FetchType.EAGER, orphanRemoval = true)
public Collection<FooBar> getFooBars() {
return fooBars;
}
將這種復制發布到GitHub似乎最容易 - 希望還有一個微妙的差異或我錯過的東西。
這是基於Spring Boot和H2內存數據庫所以應該沒有其他環境 - 如果有疑問,只需嘗試mvn clean test
。
FooRepositoryTest
類有測試用例。 它有一個驗證刪除鏈接FooBar
,或者它可能只是更容易讀取記錄的SQL。
編輯
我已經測試了你的場景,並進行了以下三個修改以使其工作:
Java Persistence 2.1。 第3.2.3節
操作刪除
•如果X是新實體,則刪除操作將忽略它 。 但是,如果從X到這些其他實體的關系使用cascade = REMOVE或cascade = ALL annotation元素值進行注釋,則刪除操作會級聯到由X引用的實體。
•如果X是托管實體,則刪除操作會導致其被刪除。 如果從X到這些其他實體的關系使用cascade = REMOVE或cascade = ALL注釋元素值進行注釋,則刪除操作將級聯到由X引用的實體。
檢查您是否已經為實體Foo
(或FooBar
或Bar
)使用操作persist
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.