Hibernate具有连接类级联问题的多对多问题

Kas*_*rer 6 java hibernate jpa cascade hibernate-onetomany

我和Many-to-Many班级之间有关系.因为我想获得有关辅助表的其他信息,所以我必须创建一个帮助类,如下所述:使用JPA和Hibernate时,使用额外列映射多对多关联的最佳方法FooBarFooBar

我创建了一个Foo,并创建了一些条形图(保存到DB).当我然后使用其中一个条添加到foo

foo.addBar(bar);            // adds it bidirectionally
barRepository.save(bar);    // JpaRepository
Run Code Online (Sandbox Code Playgroud)

然后创建FooBar的DB条目 - 正如预期的那样.

但是,当我想再次从foo中删除相同的栏时,使用

foo.removeBar(bar);         // removes it bidirectionally
barRepository.save(bar);    // JpaRepository
Run Code Online (Sandbox Code Playgroud)

然后,不会从数据库中删除先前创建的FooBar条目.通过调试,我看到foo.removeBar(bar);确实删除了双向.没有异常被抛出.

难道我做错了什么?我很确定它与Cascading选项有关,因为我只保存吧.


我尝试过的:

  • 添加orphanRemoval = true@OneToMany - 注释,但没有用.我认为这是正确的,因为我不删除 Foo和Bar,只删除他们的关系.

  • 从@OneToMany注释中排除CascadeType.REMOVE,但与orphanRemoval相同我认为这不适用于这种情况.


编辑: 我怀疑在我的代码或模型中必须有一些东西与我的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);
    }

}
Run Code Online (Sandbox Code Playgroud)
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;
    }
}
Run Code Online (Sandbox Code Playgroud)
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
}
Run Code Online (Sandbox Code Playgroud)

df7*_*899 2

我从示例代码中尝试了这一点。通过一些“草图”,重现了该错误。

不过,该解决方案确实很简单,只需添加orphanRemoval = true您提到的内容即可。在Foo.getFooBars()

@OneToMany(cascade = CascadeType.ALL, mappedBy = "foo", fetch = FetchType.EAGER, orphanRemoval = true)
public Collection<FooBar> getFooBars() {
    return fooBars;
}
Run Code Online (Sandbox Code Playgroud)

将复制品发布到GitHub似乎是最简单的- 希望那里有进一步的细微差别或我错过的东西。

这是基于 Spring Boot 和 H2 内存数据库,因此不应在其他环境下工作 -mvn clean test如果有疑问,请尝试。

班级FooRepositoryTest有测试用例。它具有删除链接的验证FooBar,或者可能更容易读取记录的 SQL。


编辑

这是下面评论中提到的屏幕截图: deleteOrphans() 断点