【问题标题】:Spring-Boot Query SELECT * FROM book (MANY to MANY rel with user) doesn't work properlySpring-Boot Query SELECT * FROM book (MANY to MANY rel with user) 不能正常工作
【发布时间】:2019-09-15 04:04:37
【问题描述】:

我正在尝试从我的数据库中返回所有书籍,但是一旦我将值插入名为 COLLECTION 的连接表(用于解决 BOOK 和 USER 之间的多对多关系),我收到的输出看起来就像一个循环(用邮递员测试)。

书籍实体的实现:

@Getter
@Setter
@ToString
@EqualsAndHashCode
@NoArgsConstructor
@AllArgsConstructor

@Entity
public class Book {

    @Id
    private Integer id;
    private String title;
    private String author;
    private String description;

    @OneToMany(mappedBy = "book", cascade = CascadeType.ALL)
    private Set<Collection> collections;

    public Book(String title, String author, String description) {
        this.title = title;
        this.author = author;
        this.description = description; 
}

    public Book(String title, String author Collection... collections){
        this.title = title;
        this.author = author;

        for (Collection collection : collections){
            collection.setBook(this);
        }
        this.collections = Stream.of(collections).collect(Collectors.toSet());
    }
}

用户实体的实现:

@Getter
@Setter
@NoArgsConstructor

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String email;
    private String password;
    private String username;

    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
    private Set<Collection> collections = new HashSet<>();

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }
}

集合实体:

@Getter
@Setter
@NoArgsConstructor

@Entity
public class Collection implements Serializable {
    @Id
    @ManyToOne
    @JoinColumn
    private Book book;

    @Id
    @ManyToOne
    @JoinColumn
    private User user;

 public Collection(User user){
        this.user = user;
}
 @Override
    public boolean equals(Object o){
        if(this == o) return true;
        if(!(o instanceof Collection)) return false;
        Collection that = (Collection) o;
        return  Objects.equals(book.getTitle(), that.book.getTitle()) &&
                Objects.equals(book.getAuthor(), that.book.getAuthor()) &&
                Objects.equals(user.getUsername(), that.user.getUsername());
}
 @Override
    public int hashCode(){
        return Objects.hash(book.getTitle(), book.getAuthor(), user.getUsername());
    }
}

最后是 BookRepository:

@Transactional
@Repository
public interface BookRepository extends JpaRepository<Book, Integer> {
// this causes sql syntax error
//    @Query(value = "SELECT b.id, b.title, b.author FROM book b", nativeQuery =  true)
//    List<Book> getAllBooks();

// this returns the loopy output from postman detailed below 
     List<Book> findAll();
}

我在 Postman 中收到的输出看起来像一个循环:

[{"id":1,"title":"Pride and Prejudice","author":"Jane Austen","users":[{"id":1,"email":"a@a.com","password":"$2a$10$BVXUCumzWyec9zEUeCv1r.m2pFwvAe7Cp1dLjiGfXuEEIHkhn3jHO","username":"user","books":[{"id":1,"title":"Pride and Prejudice","author":"Jane Austen", "users":[{"id":1,"email":"a@a.com","password":"$2a$10$BVXUCumzWyec9zEUeCv1r.m2pFwvAe7Cp1dLjiGfXuEEIHkhn3jHO, "username":"user","books": .......

预期的输出应该是我在数据库中所有书籍的列表。

【问题讨论】:

  • 请使用@ManyToMany 注释,而不是@ManyToOne 与垃圾实体。另外,不要滥用 lombok 注释,不要在实体上使用@ToString,这会造成toString() 调用的无限循环。

标签: hibernate spring-boot jpa many-to-many findall


【解决方案1】:

要设置书籍和用户之间的关系,使用@ManyToMany 映射设置直接关系。 作为参考,您可以选择以下链接-

https://www.callicoder.com/hibernate-spring-boot-jpa-many-to-many-mapping-example/

另外你不需要显式定义 findAll(),Jpa 仓库自己提供了这些通用方法。

【讨论】:

  • 我按照您链接我的教程进行操作,但我遇到了同样的问题,这是由那些集合(用于连接表)引起的,一旦这些集合表中的条目会给出循环输出。在我填充 Collection 表之前,我得到了 findAll().[ { "id": 1,"title": "P", "author": "A", "description": "d", “用户”:[] }, ...]。将条目添加到表后,它会变得循环。据我了解,我需要一个明确的查询,因为它返回用户集合,当我只想显示所有书籍时,这与我无关。
  • 通过在映射字段上应用 FetchType.LAZY 进行检查。默认情况下,这设置为 FetchType.Eager,这意味着它会获取所有子实体以及父实体并继续处理。
  • 我已经有了 FetchType.LAZY。这是代码:public class Book { @ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE}) @JoinTable(name = "collection", joinColumns = { @JoinColumn(name = "book_id") }, inverseJoinColumns = { @JoinColumn(name = "user_id") }) private Set&lt;User&gt; users = new HashSet&lt;&gt;(); } 并且:``public class User{ @ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE}, mappedBy = "users") private Set books =新哈希集(); }``
  • 您是否使用转换器将实体更改为 bean?
  • 我设法通过使用 DTO 并将 Book 转换为 BookDTO 解决了这个问题。非常感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 2019-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多