Java 在JPA中的两个相关实体中,都会出现在某些急切的n-to-n关系中进行更新的情况

Java 在JPA中的两个相关实体中,都会出现在某些急切的n-to-n关系中进行更新的情况,java,jpa,persistence,many-to-many,eager-loading,Java,Jpa,Persistence,Many To Many,Eager Loading,改变JPA中两个实体之间n对n关系的最佳方式是什么 让我用一个例子来解释:假设我有一个作者和一个书实体,其中书可以有各种作者s,而作者可以写各种书s。此模型表示为n对n的渴望关系: @Entity public class Author { @ManyToMany(fetch=FetchType.EAGER) private List<Book> books; // ... } 或者从作者的书籍中删除书籍: public class SomeOtherSer

改变JPA中两个实体之间n对n关系的最佳方式是什么

让我用一个例子来解释:假设我有一个
作者
和一个
实体,其中
可以有各种
作者
s,而
作者
可以写各种
s。此模型表示为n对n的渴望关系:

@Entity
public class Author {
    @ManyToMany(fetch=FetchType.EAGER)
    private List<Book> books;
    // ...
}
或者从
作者的书籍中删除
书籍

public class SomeOtherService {
    public void removeBook(Author author, Book book) {
        author.getBooks().remove(book);
        em.persist(author);
    }
}
但是,我希望在不更新的实体中注册更新。当我调用
addAuthor()
时,我希望更新的
书籍也会出现在
作者的书籍列表中。我想在调用
removeBook()
时,将
作者
书籍
的作者列表中删除

如果代码与上述代码相同,则不会发生。我当前的解决方案是在两个实体中执行反对应操作,大致如下所示:

public class SomeService {
    public void addAuthor(Book book, Author author)  {
        book.getAuthors().add(author);
        author.getBooks().add(book);
        em.persist(book);
        em.persist(author);
    }
}
不过,对我来说,这似乎是一个蹩脚的解决方案。所以,我的问题是:有没有更好的方法


提前感谢?

查看@PreXXXX和@PostXXXX注释。根据您正在使用的数据库,您最好进入并编写自己的触发器

如果你正在寻找最不可知论的方法,那么你所提出的解决方案应该会奏效

编辑:
另一种方法是保存触发器代码,并在CRUD之后将其作为本机SQL运行(假设您在测试中创建并删除)。

对我来说,这并不是一个真正的跛脚解决方案,因为它对正在发生的事情非常明确,一个优点是您有一个非常明确的代码。然而,如果对你来说,这是过于明确,那么你有几个选择

正如Jay所建议的那样,您可以编写一个@PreUpdate回调方法来执行以下操作:

author.getBooks().add(book);
但是,要使其起作用,您必须使用@manytomy注释的cascade属性将更改级联到作者

@ManyToMany(cascade=CascadeType.ALL)
例如,也可以增加级联类型的粒度

还有一种替代方法是通过委托方法处理集合。 这样做的好处是,您可以完全控制addAuthor方法,但对使用您的实体的人来说,直观性较差。 它可以写为:

public void addAuthor(Author A) {
this.getAuthors().add(a);
a.addBook(this);
}
然后需要实现addBook。和级联变化


你的选择也不错。您可以使用helper类来实现这一点,但这会增加复杂性,因此在您的头脑中。

维护双向关系状态可能是一项挑战。最后两者都

book.getAuthors().add(author);
author.getBooks().add(book);
需要打电话


在我工作的地方,我们使用aspectJ和一些内部元数据来处理关联双方的设置。对于小项目来说,这有点过头了,而且你做的方式很好。

文森特·帕丁顿曾经写过一篇博文,我相信你会对此感兴趣。本质上,他建议在关系中的每个伙伴上都有两个关系添加方法:一个是内部(可能是包范围内的)方法,它只向集合添加一个项,另一个是外部方法,它调用两个伙伴上的内部方法。同样的模式也可以应用于删除方法。

很抱歉我不知道,但我不知道DB中的触发器在这里有什么用处。你能解释一下吗?
public void addAuthor(Author A) {
this.getAuthors().add(a);
a.addBook(this);
}
book.getAuthors().add(author);
author.getBooks().add(book);