我有一个Book
实体,它有两个子实体Author
和Genre
,每个子实体都有一个ManyToMany关系和相应的连接表。Book
类定义如下:
@Entity
@Getter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "book_seq")
@GenericGenerator(name = "book_seq",
strategy = "com.example.bookappjpa.dao.StringPrefixedSequenceIdGenerator",
parameters = {
@org.hibernate.annotations.Parameter(name = StringPrefixedSequenceIdGenerator.INCREMENT_PARAM, value = "1"),
@org.hibernate.annotations.Parameter(name = StringPrefixedSequenceIdGenerator.VALUE_PREFIX_PARAMETER, value = "B"),
@org.hibernate.annotations.Parameter(name = StringPrefixedSequenceIdGenerator.NUMBER_FORMAT_PARAMETER, value = "%08d"),
})
private String id;
@NaturalId
private String title;
@Column(name = "rank_no")
private int rank;
private int listId;
private Double rating;
private int pages;
private LocalDate publishedOn;
@ManyToMany()
@JoinTable(name = "BOOK_AUTHOR", joinColumns = @JoinColumn(name = "BOOK_ID"), inverseJoinColumns = @JoinColumn(name = "AUTHOR_ID")
)
private Set<Author> authors = new HashSet<>();
@ManyToMany
@JoinTable(name = "BOOK_GENRE", joinColumns = @JoinColumn(name = "BOOK_ID"), inverseJoinColumns = @JoinColumn(name = "GENRE_ID"))
private Set<Genre> genres = new HashSet<>();
public void setTitle(String title) {
this.title = title;
}
public void setRankNo(int rankNo) {
this.rank = rankNo;
}
public void setListId(int listId) {
this.listId = listId;
}
public void setRating(Double rating) {
this.rating = rating;
}
public void setPages(int pages) {
this.pages = pages;
}
public void setPublishedOn(LocalDate publishedOn) {
this.publishedOn = publishedOn;
}
public boolean addAuthor(Author author) {
return this.authors.add(author);
}
public boolean addGenre(Genre genre) {
return this.genres.add(genre);
}
}
字符串
持久化方法(通过其自然id查找每个实体,以查看它是否已经存在于DB中,如果不存在,则仅继续持久化。请原谅半成品代码,有待改进):
@Transactional
public void addBook(BookDTO book) {
Session session = entityManager.unwrap(Session.class);
Book b = session.bySimpleNaturalId(Book.class).load(book.getTitle());
if (null == b) {
Book bookToDB = new Book();
bookToDB.setTitle(book.getTitle());
bookToDB.setPages(book.getPages());
bookToDB.setRating(book.getRating());
bookToDB.setRankNo(book.getRank());
bookToDB.setPublishedOn(book.getPublishedOn());
book.getAuthors().forEach(a -> {
Author authorToDB = new Author(a.getName(), a.getAge(), a.getNationality());
if(null == session.bySimpleNaturalId(Author.class).load(a.getName())) {
authorToDB.addBook(bookToDB);
entityManager.persist(authorToDB);
}
});
book.getGenres().forEach(g -> {
if(null == session.bySimpleNaturalId(Genre.class).load(g.getName())) {
Genre genreToDB = new Genre(g.getName());
genreToDB.addBook(bookToDB);
entityManager.persist(genreToDB);
}
});
entityManager.persist(bookToDB);
} else {
String message = "Book with title " + book.getTitle() + " already exists!";
log.info(message);
throw new RuntimeException(message);
}
session.close();
}
型
这种方法的问题是,例如,如果某本书使用特定的Author
和Genre
持久化(s),稍后,我们有另一个Book
,具有相同的Author
和Genre
(s),将按照上面的代码跳过子实体的持久化,并且在连接表中不填充任何内容,表示父Book
和子Author
/Genre
(s)之间没有关系。我真的应该为Author
和Genre
实体包括上面的检查吗?如果没有,我将在相应的实体表中得到多个实体,它们具有相同的Author
和Genre
名称,尽管具有不同的ID序列号(主键)。我不确定这是不是一个好的练习。想知道是否有一种复杂的/effii方法来处理生产级代码中的这种情况。提前感谢,如果这是一个新手的问题,我道歉
两个Book对象具有相同的作者(第二个没有进入连接表BOOK_AUTHOR,因为作者已经存在于DB中,并且我的DAO方法在这种情况下不允许再次持久化):
{
"rank": 8,
"title": "Clap When You Land",
"authors": [
{
"name": "Elizabeth Acevedo",
"age": 0,
"nationality": null
}
],
"rating": 0,
"genres": [
{
"name": "Young Adult"
},
{
"name": "Poetry"
},
{
"name": "Contemporary"
},
{
"name": "Fiction"
},
{
"name": "Audiobook"
},
{
"name": "LGBT"
},
{
"name": "Realistic Fiction"
}
],
"pages": 432,
"publishedOn": "2020-05-05",
"listId": 1
}
{
"rank": 18,
"title": "The Poet X",
"authors": [
{
"name": "Elizabeth Acevedo",
"age": 0,
"nationality": null
}
],
"rating": 0,
"genres": [
{
"name": "Poetry"
},
{
"name": "Young Adult"
},
{
"name": "Contemporary"
},
{
"name": "Fiction"
},
{
"name": "Audiobook"
},
{
"name": "Realistic Fiction"
},
{
"name": "Romance"
}
],
"pages": 368,
"publishedOn": "2018-03-06",
"listId": 1
}
型
1条答案
按热度按时间yh2wf1be1#
要保持关系的一致性,并确保将现有的体裁和作者添加到新书中:
通过自然ID获取流派和作者,并执行以下操作
字符串
您的Genre和Author实体应该包括以下与书籍的双向关系
型
并在Book实体中展开addAuthor(...)和addGenre(...)方法,以确保在添加它们时双向关系是同步的
型