spring-data-jpa 多对多 findByID
spring-data-jpa many to many findByID
我在书和作者之间有多对多关系,我有 3 个表:作者、书和 author_book。
@Entity()
@Table(name = "author")
public class Author implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinTable(
name = "author_book",
joinColumns = @JoinColumn(name = "author_id"),
inverseJoinColumns = @JoinColumn(name = "book_id")
)
private List<Book> authorBooks = new ArrayList<Book>();
public Author() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Book> getAuthorBooks() {
return authorBooks;
}
public void setAuthorBooks(List<Book> authorBooks) {
this.authorBooks = authorBooks;
}
@Override
public String toString() {
return "Author{" + "name=" + name + ", authorBooks=" + authorBooks + '}';
}
}
@Entity()
@Table(name = "book")
public class Book implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
@ManyToMany(mappedBy = "authorBooks", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Author> bookAuthors = new ArrayList<Author>();
public Book() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Author> getBookAuthors() {
return bookAuthors;
}
public void setBookAuthors(List<Author> bookAuthors) {
this.bookAuthors = bookAuthors;
}
@Override
public String toString() {
return "Book{" + "name=" + name + ", bookAuthors=" + bookAuthors + '}';
}
}
我可以毫无问题地将数据添加到数据库,但是当我想通过其 id 获取作者或书籍时
Optional<Author> optionalAuthor = authorReposi.findById(1L);
System.out.println("Author: " + optionalAuthor.get().toString());
我得到一个错误:LazyInitialization 延迟失败...
我想使用 FetchType.LAZY 并获取作者或书籍的实例。
感谢您的宝贵时间。
所以,阅读精美手册:6.3.10. Configuring Fetch- and LoadGraphs。
您的问题只是您的 toString()
方法是递归的。 Authors
表示打印 Books
,Books
表示打印 Authors
。专业提示:成功在于细节。
对于 load
或 fetch
,您需要使用 JPA
中的 EntityGraph
来指定连接的属性。所以:
@Entity()
@Table(name = "author")
@NamedEntityGraph(name = "Book.detail", attributeNodes = @NamedAttributeNode("books"))
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Author {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
@ManyToMany
private List<Book> books;
}
和
@Entity()
@Table(name = "book")
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
@ManyToMany(mappedBy = "books")
private List<Author> authors;
}
有存储库:
public interface AuthorRepository extends JpaRepository<Author, Long>{
@EntityGraph(value = "Book.detail", type = EntityGraphType.LOAD)
Author getById(Long id);
}
和
public interface BookRepository extends JpaRepository<Book, Long>{
}
然后你必须自己打印你想要的。基本上,把 toStrings
放在 Entities
中通常会导致问题,但你也应该 RTFM.
private void read(Long id) {
Author a = authorRepository.getById(id);
System.out.println("Author: " + a.getName());
for( Book b: a.getBooks()) {
System.out.println("\tBook: " + b.getName());
}
}
最后,我避免像瘟疫一样使用 Cascade
注释。它们是复杂的注释。此外,ManyToMany
默认为 FetchType.LAZY
。重要的注释是 mappedBy
注释。这会告诉您哪个实体拥有该关系。拥有实体是负责保持关系的实体。双向注释的另一面实际上只用于查询。不需要在实体中创建新的 ArrayList
,因为它们在查询期间无论如何都会被丢弃。当您需要保留一个新的 Author
具有关系的实体时,只需创建一个列表,否则使用查询返回的列表。
private Author save() {
Book b = bookRepository.save(Book.builder().name("b1").build());
return authorRepository.save(Author.builder().name("a1").books(Collections.singletonList(b)).build());
}
我在书和作者之间有多对多关系,我有 3 个表:作者、书和 author_book。
@Entity()
@Table(name = "author")
public class Author implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinTable(
name = "author_book",
joinColumns = @JoinColumn(name = "author_id"),
inverseJoinColumns = @JoinColumn(name = "book_id")
)
private List<Book> authorBooks = new ArrayList<Book>();
public Author() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Book> getAuthorBooks() {
return authorBooks;
}
public void setAuthorBooks(List<Book> authorBooks) {
this.authorBooks = authorBooks;
}
@Override
public String toString() {
return "Author{" + "name=" + name + ", authorBooks=" + authorBooks + '}';
}
}
@Entity()
@Table(name = "book")
public class Book implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
@ManyToMany(mappedBy = "authorBooks", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Author> bookAuthors = new ArrayList<Author>();
public Book() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Author> getBookAuthors() {
return bookAuthors;
}
public void setBookAuthors(List<Author> bookAuthors) {
this.bookAuthors = bookAuthors;
}
@Override
public String toString() {
return "Book{" + "name=" + name + ", bookAuthors=" + bookAuthors + '}';
}
}
我可以毫无问题地将数据添加到数据库,但是当我想通过其 id 获取作者或书籍时
Optional<Author> optionalAuthor = authorReposi.findById(1L);
System.out.println("Author: " + optionalAuthor.get().toString());
我得到一个错误:LazyInitialization 延迟失败...
我想使用 FetchType.LAZY 并获取作者或书籍的实例。
感谢您的宝贵时间。
所以,阅读精美手册:6.3.10. Configuring Fetch- and LoadGraphs。
您的问题只是您的 toString()
方法是递归的。 Authors
表示打印 Books
,Books
表示打印 Authors
。专业提示:成功在于细节。
对于 load
或 fetch
,您需要使用 JPA
中的 EntityGraph
来指定连接的属性。所以:
@Entity()
@Table(name = "author")
@NamedEntityGraph(name = "Book.detail", attributeNodes = @NamedAttributeNode("books"))
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Author {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
@ManyToMany
private List<Book> books;
}
和
@Entity()
@Table(name = "book")
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
@ManyToMany(mappedBy = "books")
private List<Author> authors;
}
有存储库:
public interface AuthorRepository extends JpaRepository<Author, Long>{
@EntityGraph(value = "Book.detail", type = EntityGraphType.LOAD)
Author getById(Long id);
}
和
public interface BookRepository extends JpaRepository<Book, Long>{
}
然后你必须自己打印你想要的。基本上,把 toStrings
放在 Entities
中通常会导致问题,但你也应该 RTFM.
private void read(Long id) {
Author a = authorRepository.getById(id);
System.out.println("Author: " + a.getName());
for( Book b: a.getBooks()) {
System.out.println("\tBook: " + b.getName());
}
}
最后,我避免像瘟疫一样使用 Cascade
注释。它们是复杂的注释。此外,ManyToMany
默认为 FetchType.LAZY
。重要的注释是 mappedBy
注释。这会告诉您哪个实体拥有该关系。拥有实体是负责保持关系的实体。双向注释的另一面实际上只用于查询。不需要在实体中创建新的 ArrayList
,因为它们在查询期间无论如何都会被丢弃。当您需要保留一个新的 Author
具有关系的实体时,只需创建一个列表,否则使用查询返回的列表。
private Author save() {
Book b = bookRepository.save(Book.builder().name("b1").build());
return authorRepository.save(Author.builder().name("a1").books(Collections.singletonList(b)).build());
}