如何在JPA中持久化具有与其他实体存在多对多关联的实体?

huangapple 未分类评论56阅读模式
英文:

How to persist an entity having a ManyToMany association with other entity in JPA?

问题

以下是已经翻译好的内容:

@Entity
@NoArgsConstructor
@AllArgsConstructor
@Data
@Table(name = "book")
public class Book {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="book_id")
    private Integer Id;

    private String title;

    private String imgurl;

    private String description;
    private String bookpath;
    @ManyToOne
    private Author author;


    @ManyToMany(cascade = CascadeType.ALL)
    @JoinTable(name = "book_genre",
            joinColumns = @JoinColumn(name="book_id"),
            inverseJoinColumns = @JoinColumn(name="genre_id"))
    private List<Genre> genres;

    public void addGenre(Genre genre){
        this.genres.add(genre);
        genre.getBooks().add(this);
    }
}


@NoArgsConstructor
@AllArgsConstructor
@Entity
@Data
@Table(name = "genre")
public class Genre {
    @Id
    @Column(name="genre_id")
    private Integer id;

    private String name;


    @JsonIgnore
    @ManyToMany(cascade = CascadeType.ALL)
    @JoinTable(name="book_genre",
            joinColumns=@JoinColumn(name="genre_id"),
            inverseJoinColumns=@JoinColumn(name="book_id"))
    private List<Book> books;

    public List<Book> getBooks(){
        return this.books;
    }
}

@PostMapping("/books")
Book createBook(@RequestBody Book book){
    return this.bookRepository.save(book);
}

在 Postman 中的 JSON 数据:

{
    "title": "Evgenij Onegin",
    "imgurl": "https://biblioteka.msu.edu.mk/images/covers/2018/September/5bab75a75007c/821.806.jpeg",
    "description": "desctiption",
    "bookpath": "Books\\book1.pdf",
    "author": {
        "name": "Alexandar",
        "surname": "Puskin",
        "birthdate": "1799-06-05",
        "description": "Russian author",
        "location": "Russia",
        "category": {
            "name": "Romantism",
            "id": 1
        },
        "id": 1
    },
    "genres": [
        {
            "id": 1,
            "name": "Trailer"
        },
        {
            "id": 2,
            "name": "Comic"
        }
    ]
}

错误信息:

constraint ["PRIMARY KEY ON PUBLIC.GENRE(GENRE_ID)'.

问题似乎出现在 ManyToMany 关系中。不添加 Genre 到 Book 时,一切正常,但我希望能够添加它。

英文:

I am not able to add new Book with existing Genre in SpringBoot from json in Postman. It says 'constraint [&quot;PRIMARY KEY ON PUBLIC.GENRE(GENRE_ID)'.

Here is my model:

@Entity
@NoArgsConstructor
@AllArgsConstructor
@Data
@Table(name = &quot;book&quot;)
public class Book {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name=&quot;book_id&quot;)
    private Integer Id;

    private String title;

    private String imgurl;

    private String description;
    private String bookpath;
    @ManyToOne
    private Author author;


    @ManyToMany(cascade = CascadeType.ALL)
    @JoinTable(name = &quot;book_genre&quot;,
            joinColumns = @JoinColumn(name=&quot;book_id&quot;),
            inverseJoinColumns = @JoinColumn(name=&quot;genre_id&quot;))
    private List&lt;Genre&gt; genres;

    public void addGenre(Genre genre){
        this.genres.add(genre);
        genre.getBooks().add(this);
    }



}





@NoArgsConstructor
@AllArgsConstructor
@Entity
@Data
@Table(name = &quot;genre&quot;)
public class Genre {
    @Id
    @Column(name=&quot;genre_id&quot;)
    private Integer id;

    private String name;


    @JsonIgnore
    @ManyToMany(cascade = CascadeType.ALL)
    @JoinTable(name=&quot;book_genre&quot;,
            joinColumns=@JoinColumn(name=&quot;genre_id&quot;),
            inverseJoinColumns=@JoinColumn(name=&quot;book_id&quot;))
    private List&lt;Book&gt; books;

    public List&lt;Book&gt; getBooks(){
        return this.books;
    }


}

I am working with jpa Repository. Here is my book controller post method:

@PostMapping(&quot;/books&quot;)
    Book createBook(@RequestBody Book book){
        return this.bookRepository.save(book);
    }

In postman I have this:

{
    &quot;title&quot;: &quot;Evgenij Onegin&quot;,
    &quot;imgurl&quot;: &quot;https://biblioteka.msu.edu.mk/images/covers/2018/September/5bab75a75007c/821.806.jpeg&quot;,
    &quot;description&quot;: &quot;desctiption&quot;,
    &quot;bookpath&quot;: &quot;Books\\book1.pdf&quot;,
    &quot;author&quot;: {
        &quot;name&quot;: &quot;Alexandar&quot;,
        &quot;surname&quot;: &quot;Puskin&quot;,
        &quot;birthdate&quot;: &quot;1799-06-05&quot;,
        &quot;description&quot;: &quot;Russian author&quot;,
        &quot;location&quot;: &quot;Russia&quot;,
        &quot;category&quot;: {
            &quot;name&quot;: &quot;Romantism&quot;,
            &quot;id&quot;: 1
        },
        &quot;id&quot;: 1
    },
    &quot;genres&quot;: [
        {
            &quot;id&quot;: 1,
            &quot;name&quot;: &quot;Trailer&quot;
        },
        {
            &quot;id&quot;: 2,
            &quot;name&quot;: &quot;Comic&quot;
        }
    ]
}

And the error I am getting:

constraint [\&quot;PRIMARY KEY ON PUBLIC.GENRE(GENRE_ID)&#39;.

So it seems like the problem is in ManyToMany relationship. Without adding Genre to Book it works perfect, but I want to add it.

答案1

得分: 0

你的ManyToMany关联使用方法不正确。你在两端都定义了JoinTable

public class Book {
 ...
  @ManyToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE } )
  @JoinTable(name = "book_genre",
    joinColumns = @JoinColumn(name = "book_id"),
    inverseJoinColumns = @JoinColumn(name = "genre_id")
  )
  private List<Genre> genres;
 ...
}

另一侧在Genre中只需这样:

public class Genre {
  ...
  @ManyToMany(mappedBy = "genres")
  private List<Book> books;
  ...
}

这是一篇关于JPA和Hibernate中使用@ManyToMany注解的最佳实践文章,它将帮助你理解关联映射。

英文:

You are doing the ManyToMany association incorrect. You are defining the JoinTable on the both end

public class Book {
 ...
  @ManyToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE } )
  @JoinTable(name = &quot;book_genre&quot;,
    joinColumns = @JoinColumn(name = &quot;book_id&quot;),
    inverseJoinColumns = @JoinColumn(name = &quot;genre_id&quot;)
  )
  private List&lt;Genre&gt; genres;
 ...

}

And on the other side in Genre you just do this

public class Genre {
  ...
  @ManyToMany(mappedBy = &quot;genres&quot;)
  private List&lt;Book&gt; books;
  ...
}

This is a very good article about The best way to use the @ManyToMany annotation with JPA and Hibernate This will help you understading the association mappings.

答案2

得分: 0

你应该在你的@ManyToMany映射中的Books和Genre两处都使用CascadeType.PERSIST。同时,Genre实体中的books应该由genres集合进行映射。

// Book实体:
@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
@JoinTable(name = "book_genre",
        joinColumns = @JoinColumn(name="book_id"),
        inverseJoinColumns = @JoinColumn(name="genre_id"))
private List<Genre> genres;

// Genre实体:
@ManyToMany(mappedBy = "genres", fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
private List<Book> books;

来源: https://www.javaworld.com/article/3387643/java-persistence-with-jpa-and-hibernate-part-2-many-to-many-relationships.html

英文:

You should have used CascadeType.PERSIST in both of your @ManyToMany mappings for Books and Genre.
Also, books in Genre entity should be mapped by genres collection.

// Book entity:
    @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
    @JoinTable(name = &quot;book_genre&quot;,
            joinColumns = @JoinColumn(name=&quot;book_id&quot;),
            inverseJoinColumns = @JoinColumn(name=&quot;genre_id&quot;))
    private List&lt;Genre&gt; genres;

// Genre entity:
    @ManyToMany(mappedBy = &quot;genres&quot;, fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
    private List&lt;Book&gt; books;

By: https://www.javaworld.com/article/3387643/java-persistence-with-jpa-and-hibernate-part-2-many-to-many-relationships.html

huangapple
  • 本文由 发表于 2020年4月11日 01:49:19
  • 转载请务必保留本文链接:https://java.coder-hub.com/61145793.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定