我正在使用Spring Data JPA和H2数据库开发Spring Boot应用程序。我正在使用spring-data-jpa。 当我使用ManyToMany mapper类来获取另一个类的数据时。但我发现它是NULL。
Book.class
@Entity
public class Book implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue
private Integer id;
private String name;
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "BOOK_AUTHOR", joinColumns = {
@JoinColumn(name = "BOOK_ID", referencedColumnName = "ID")}, inverseJoinColumns = {
@JoinColumn(name = "AUTHOR_ID", referencedColumnName = "ID")})
private Set<Author> authors;
public Book() {
super();
}
public Book(String name) {
super();
this.name = name;
this.authors = new HashSet<>();
}
public Book(String name, Set<Author> authors) {
super();
this.name = name;
this.authors = authors;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Author> getAuthors() {
return authors;
}
public void setAuthors(Set<Author> authors) {
this.authors = authors;
}
@Override
public String toString() {
return String.format("Book [id=%s, name=%s, authors=%s]", id, name, authors);
}
}
Author.class
@Entity
public class Author implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue
private Integer id;
private String name;
@ManyToMany(mappedBy = "authors")
private Set<Book> books;
//why CAN NOT GET the data when using these code else ?
// @ManyToMany(cascade = CascadeType.ALL)
// @JoinTable(name = "BOOK_AUTHOR", joinColumns = {
// @JoinColumn(name = "AUTHOR_ID", referencedColumnName = "ID")},
//inverseJoinColumns = {
// @JoinColumn(name = "BOOK_ID", referencedColumnName = "ID")})
// private Set<Book> books;
public Author() {
super();
}
public Author(String name) {
super();
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Book> getBooks() {
return books;
}
public void setBooks(Set<Book> books) {
this.books = books;
}
@Override
public String toString() {
return String.format("Author [id=%s, name=%s, books=%s]", id, name, books);
}
}
test.class中的测试代码snapper
List<Book> books = bookRepository.findAll();
for (Book it : books) {
Set<Author> authors = it.getAuthors();
//CAN get authors data.
System.out.println(authors.size());
}
assertThat(bookRepository.findAll()).hasSize(2);
List<Author> authors = authorRepository.findAll();
for (Author it : authors) {
//CAN NOT get books data ? Why and HOW ?
//HOW can I get the books data ? Or other ways ?
// thanks
Set<Book> books1 = it.getBooks();
assertThat(books1 == null);
}
assertThat(authorRepository.findAll()).hasSize(3);
我的代码中是否有错误? 还是其他方式?
非常感谢。
答案 0 :(得分:1)
将FetchType设置为EAGER并不好,因为它效率不高。
当然,您必须先初始化authors
和books
。
您正在使用双向 ManyToMany关系。因此,当您将图书添加到图书时,您必须使用图书手动“链接”作者:
@ManyToMany(cascade = CascadeType.ALL)
private final Set<Author> authors = new HashSet<>();
// ...
public void setAuthors(Set<Author> authors) {
for (Author author : authors) {
author.getBooks().add(this);
this.authors.add(author);
}
}
(注意author.getBooks().add(this);
)
您需要更改构造函数:
public Book(String name, Set<Author> authors) {
this.name = name;
setAuthors(authors);
}
另外,我建议更正toString
方法 - 从中移除authors
,以避免发生Stackoverflow异常(您必须在作者类中执行此操作):< / p>
@Override
public String toString() {
return String.format("Book [id=%s, name=%s]", id, name);
}
比你的测试工作正常:
@Before
public void init() {
Author lewis = new Author("Lewis");
Author mark = new Author("Mark");
Author peter = new Author("Peter");
Book spring = new Book("Spring in Action", new HashSet<>(asList(lewis, mark)));
Book springboot = new Book("Spring Boot in Action", new HashSet<>(asList(lewis, peter)));
bookRepository.save(Arrays.asList(spring, springboot));
}
@Test
public void findAll() {
List<Book> books = bookRepository.findAll();
assertThat(books).hasSize(2);
for (Book book : books) {
Set<Author> bookAuthors = book.getAuthors();
assertThat(bookAuthors).isNotNull();
assertThat(bookAuthors.size()).isGreaterThan(0);
System.out.println(book);
bookAuthors.forEach(System.out::println);
}
List<Author> authors = authorRepository.findAll();
assertThat(authors).hasSize(3);
for (Author author : authors) {
Set<Book> authorBooks = author.getBooks();
assertThat(authorBooks).isNotNull();
assertThat(authorBooks.size()).isGreaterThan(0);
System.out.println(author);
authorBooks.forEach(System.out::println);
}
}
有关详细信息,请参阅Hibernate User Guide。
一般情况下,不要将cascade = CascadeType.ALL
用于ManyToMany,因为在这种情况下,实体是独立的。请改用cascade = {CascadeType.PERSIST, CascadeType.MERGE}
。
答案 1 :(得分:0)
您可以将mappedBy = "", cascade = CascadeType.ALL, fetch = FetchType.LAZY
用于实体。在方法之前使用@Transactional(propagation = Propagation.REQUIRED)
注释并在类上使用@Transactional
。当您在多对多关系实体lilnk上使用.size()
方法获取数据时:当您获取Author
使用Author.getBooks().size();
时,您可以获得作者的启动详细信息。
例如
FOrd fOrd = orderRepo.findOne(id);
fOrd.getFOrdItems().size();
fOrd.getFOrdDetails().size();
答案 2 :(得分:0)
当我使用此代码时,迭代Set,在控制台上崩溃:
org.hibernate.LazyInitializationException:无法初始化代理 - 没有会话,加载不受欢迎
所以,我在Stackoverflow.com上搜索这些技巧。
添加
@ManyToMany(mappedBy = "authors")
private Set<Book> books = new HashSet<Book>();
使用@JB Nizet建议,谢谢!
@ManyToMany(mappedBy = "posts", fetch = FetchType.EAGER)
@JsonBackReference
谢谢大家。