加入三个表与@ManyToMany协会
我实现使用Spring引导和Spring数据JPA书店应用。我曾与@OneToOne和@ManyToOne和@OneToMany协会试过,但我坚持用@ManyToMany关联。
有三个表 - 书,流派和作者。我要做到以下几点1)创建一个新表 - Book_Genre_Author 2)如果作者或类型的数据库已经存在,它不会使数据库中的一个新条目。 3)如果本书在数据库中已经存在,它不会使一个进入数据库。 4)如何使用Spring数据JPA实现插入和更新操作?
这里是我的三个实体 -
@Entity
@Table(name = "Book_Details")
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CUSTOM_SEQUENCE")
@SequenceGenerator(sequenceName = "customer_seq", allocationSize = 1, name = "CUSTOM_SEQUENCE")
@Column(name = "BookId")
int bookId;
public int getBookId() {
return bookId;
}
public void setBookId(int bookId) {
this.bookId = bookId;
}
@Column(name = "BookName")
String bookName;
@ManyToMany(cascade=CascadeType.ALL)
@JoinTable(name = "Book_Author_Genre", joinColumns = @JoinColumn(name = "bookId"), inverseJoinColumns = @JoinColumn(name = "genreId"))
@MapKeyJoinColumn(name = "authorId")
@ElementCollection
private Map<Author, Genre> authorGenre = new HashMap<>();
public Map<Author, Genre> getAuthorGenre() {
return authorGenre;
}
public void setAuthorGenre(Map<Author, Genre> authorGenre) {
this.authorGenre = authorGenre;
}
@Column(name = "Language")
String language;
@Column(name = "GoodReadReviews")
String goodReadReviews;
@Override public String toString() { return "BookId=" + this.bookId +
"::BookName=" + this.bookName + "::AuthorId=" + "Will check how to get it" +
"::Langauge = " + this.language + "::GenreId = " + "Will check how to get it" +
"::GoodReadReviews=" + this.goodReadReviews;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
public String getGoodReadReviews() {
return goodReadReviews;
}
public void setGoodReadReviews(String goodReadReviews) {
this.goodReadReviews = goodReadReviews;
}
}
@Entity
@Table(name="Author_Details")
public class Author {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator="AuthorSeqGenerator")
@SequenceGenerator(sequenceName = "author_seq", allocationSize = 1, name = "AuthorSeqGenerator")
@Column(name="AuthorId")
int authorId;
@Column(name="AuthorName")
String authorName;
@Column(name="Country")
String country;
@Column(name="Gender")
String gender;
public int getAuthorId() {
return authorId;
}
public void setAuthorId(int authorId) {
this.authorId = authorId;
}
public String getAuthorName() {
return authorName;
}
public void setAuthorName(String authorName) {
this.authorName = authorName;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
}
@Entity
@Table(name="Genre_details")
public class Genre {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator="GenreSeqGenerator")
@SequenceGenerator(sequenceName = "genre_seq", allocationSize = 1, name = "GenreSeqGenerator")
int genreId;
@Column(name="GenreName")
String genreName;
public int getGenreId() {
return genreId;
}
public void setGenreId(int genreId) {
this.genreId = genreId;
}
public String getGenreName() {
return genreName;
}
public void setGenreName(String genreName) {
this.genreName = genreName;
}
}
我试着用下面的代码保存书籍的详细信息 -
Author author = new Author();
author.setAuthorName("Rabindranath Tagore");
author.setCountry("India");
author.setGender("Male");
Genre genre = new Genre();
genre.setGenreName("Fiction");
Book book = new Book();
book.setBookName("Gitanjali");
book.setGoodReadReviews("5");
book.setLanguage("Bengali");
HashMap<Author,Genre> authorGenre = new HashMap<>();
authorGenre.put(author, genre);
book.setAuthorGenre(authorGenre);
bookRepository.save(book);
不过,我收到以下错误。
org.springframework.dao.InvalidDataAccessApiUsageException:由造成org.hibernate.TransientObjectException:对象引用一个未保存的瞬态的实例 - 冲洗之前保存的瞬态的实例:com.bsm.app.model.Author;嵌套的例外是java.lang.IllegalStateException:org.hibernate.TransientObjectException:对象引用一个未保存的瞬态的实例 - 冲洗之前保存的瞬态的实例:com.bsm.app.model.Author
如我在它天真的我可能是错误的,我的做法。请建议和支持。
我建议建立这将被用于映射特定表的新链接的实体。
你只需要决定是否要留在一个复合主键或添加人工ID(推荐)。
这种设置似乎涉及更多的代码,但是从我的经验更为清晰,一旦3个表开始发挥作用:
class Book {
@OneToMany(mappedBy = "book", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
private Set<BookAuthorGenreLink> bookAuthorGenreLinks;
}
class Author{
@OneToMany(mappedBy = "author", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
private Set<BookAuthorGenreLink> bookAuthorGenreLinks;
}
class Genre{
@OneToMany(mappedBy = "genre", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
private Set<BookAuthorGenreLink> bookAuthorGenreLinks;
}
链接表:
class BookAuthorGenreLink {
@Id
@GeneratedValue
private Long id;
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinColumn(name = "book_id")
private Book book;
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinColumn(name = "author_id")
private Author author;
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinColumn(name = "genre_id")
private Genre genre;
}