gpt4 book ai didi

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

转载 作者:塔克拉玛干 更新时间:2023-11-03 05:23:52 26 4
gpt4 key购买 nike

我在类 FooBar 之间有一个多对多 关系。因为我想获得有关帮助程序表的其他信息,所以我必须创建一个帮助程序类 FooBar,如下所述:The best way to map a many-to-many association with extra columns when using JPA and Hibernate

我创建了一个 Foo,并创建了一些条形图(保存到数据库)。然后,当我使用

将其中一个栏添加到 foo 时
foo.addBar(bar);            // adds it bidirectionally
barRepository.save(bar); // JpaRepository

然后创建了 FooBar 的数据库条目 - 正如预期的那样。

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

foo.removeBar(bar);         // removes it bidirectionally
barRepository.save(bar); // JpaRepository

然后较早创建的 FooBar 条目不会从数据库中删除。通过调试,我看到 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
}

最佳答案

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

解决方案确实很简单,只需添加您提到的 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。


编辑

这是下面评论中提到的截图: deleteOrphans() breakpoint

关于java - 具有连接类级联问题的 Hibernate 多对多,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52442803/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com