当前位置: 首页 > 知识库问答 >
问题:

SpringDataJPA:QueryManyToMany,如何从映射类中获取数据?

经正祥
2023-03-14

我正在开发Spring Boot应用程序与Spring Data JPA和H2数据库。我使用的是sping-data-jpa。当我使用ManyTo很多映射器类来获取另一个类的数据时。但是我发现它是NULL。

代码在github上

书班

@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);
}

}

著者班

@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);
}

}

测试中的测试代码捕捉器。班

    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);

我的代码有错误吗?或者其他方式?

非常感谢。

共有3个答案

柴瀚
2023-03-14

当我使用此代码迭代器Set时,在控制台上崩溃:

组织。冬眠LazyInitializationException:无法初始化代理-无会话,encore un fois

所以,我在tackoverflow.com.上搜索这个提示

这个答案对我有帮助

只是加上

@ManyToMany(mappedBy = "authors")
private Set<Book> books = new HashSet<Book>();

使用@JB Nizet建议,谢谢!

@ManyToMany(mappedBy = "posts", fetch = FetchType.EAGER)
@JsonBackReference

谢谢大家。

秦承允
2023-03-14

您可以使用mappdBy = "", 层叠=CascadeType。ALL, FetchType=FetchType.LAZY到实体. use@Transactional(传播=传播。当您获取数据时,请在多对多关系实体上使用. size()方法lilnk:当您获取作者使用Author.getBooks(). size();可以获取作者的引导详细信息。

例子

FOrd fOrd = orderRepo.findOne(id);
    fOrd.getFOrdItems().size();
    fOrd.getFOrdDetails().size();

何骞尧
2023-03-14

将FetchType设置为“急切”是不好的,因为这样做效率不高。当然,您必须首先初始化作者书籍

您使用的是双向ManyTo很多关系。因此,当您将作者添加到本书中时,您必须手动将他们与本书“链接”:

@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方法-从其中删除作者,以避免Stackoverflow异常的发生(您必须在作者类中也这样做):

@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用户指南。

通常不要使用cascade=CascadeType。所有适用于多个,因为在这种情况下,实体是独立的。改用cascade={CascadeType.PERSIST,CascadeType.MERGE}

 类似资料:
  • 我试着从地图上得到这样一个随机元素 但我认为最好的方法是使用谓词 我读过这个https://docs.hazelcast.com/imdg/4.2/query/how-distributed-query-works.html#querying-with-sql-like-predicates不幸的是这对我没有帮助 我找不到办法 在sql中是这样的 如何在hazelcast中生成正确的谓词? 你能举

  • 我有MyEntity类: 在@RestController中有2个@GetMapping方法。第一个: 第二个: 需要提供: 1.@GetMap返回MyEntity类中描述的实体。 2.@GetMap("url")返回实体,就像它的一个字段带有@JsonIgnore一样。 更新: 例如,当我返回我的实体时,客户端将得到: 我想在同一时间使用相同的ENTITY有机会根据URL发送给客户端: 1. 2

  • 我有这个endpoint(删除了所有不相关的endpoint),我想看看如何直接从参数映射中获取文件名列表: 第一个@RequestParam是使“file”参数成为必需的, 第二个@RequestParam是将所有参数放入映射中,而不是单独获取 即。:http://localhost:8080/files?file=first

  • 问题内容: 为了验证我收到的数据,我需要确保该长度不会超过数据库列的长度。现在,所有长度信息都存储在Hibernate映射文件中,是否可以通过编程方式访问此信息? 问题答案: 您可以实现,但这并不容易。您可能想要在启动时执行以下操作,并存储值的静态缓存。有很多特殊情况要处理(继承等),但它应适用于简单的单列映射。我可能遗漏了一些instanceof和null检查。

  • 问题内容: 似乎mmap接口仅支持readline()。如果我尝试遍历对象,则会得到字符而不是完整的行。 逐行读取mmap文件的“ pythonic”方法是什么? 问题答案: 遍历an行的最简洁方法是 请注意,在Python 3的前哨参数必须是类型的,而在Python 2它需要一个(即,而不是)。

  • 我试图在URL数组上循环,并在该URL的endpoint获取数据,然后将其作为JSON对象存储在数组中(allData)。当我运行代码并检查allData中的内容时,它是一个空数组。这告诉我,我没有正确地从机场返回。地图如果数据来自异步函数,我该如何做呢。下面是我的代码。谢谢