【发布时间】:2019-02-25 19:25:03
【问题描述】:
我在 Foo 和 Bar 类之间有 Many-to-Many 关系。因为我想获得有关辅助表的更多信息,所以我必须创建一个辅助类 FooBar,如下所述:The best way to map a many-to-many association with extra columns when using JPA and 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-entry 会不从数据库中删除。
通过调试,我看到foo.removeBar(bar); 确实是双向删除的。不抛出异常。
我做错了吗? 我很确定它与级联选项有关,因为我只保存栏。
我尝试过的:
在两个 @OneToMany 上添加
orphanRemoval = true- 注释,这不起作用。我认为这是正确的,因为我没有删除 Foo 和 Bar,只是它们的关系。从 @OneToMany 注释中排除 CascadeType.REMOVE,但与 orphanRemoval 相同,我认为这不适用于这种情况。
编辑:我怀疑我的代码或模型中一定有一些东西与我的 orphanRemoval 混淆,因为现在已经有 2 个答案说它有效(orphanRemoval=true)。
原始问题已得到解答,但如果有人知道什么可能导致我的 orphanRemoval 无法正常工作,我将非常感谢您的意见。谢谢
代码: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
}
【问题讨论】:
-
实际上,在这种情况下,孤儿删除是唯一可行的方法,因为您要从 Foo 和 Bar 的集合中删除 FooBar 引用,从而使 FooBar 成为“孤儿”。
-
正在考虑这个问题,我才意识到并非关系的所有方面都是同步的,尝试添加 fooBar.setFoo(null);和 fooBar.setBar(null);到 remove 方法
-
@Zeromus 哦,我明白你的意思了,我认为这是一个很有前途的方法。我将在午餐后立即对其进行测试,并再次向您发送结果。感谢您的建议!
-
@Zeromus 没用。我差点以为我们做到了:(
标签: java hibernate jpa cascade hibernate-onetomany