java—如何在SpringBootJPA中从列实体进行分页存储库调用

gdrx4gfi  于 2021-07-06  发布在  Java
关注(0)|答案(1)|浏览(351)

我有一个实体模型类(book),作者可以在其中编写多本书。

@Entity
@Table(name="book")
public class Book {

    @Id
    @GeneratedValue
    private Long id;

    @Column(name="book_name")
    private String bookName;

    @Column(name="author_id")
    private Long authorId;

    //Setters and getters
}

在我的spring boot项目中,我不希望有author表,因为有一个第三方服务定义了作者及其id,我如何为所有authord及其书籍调用分页存储库?
我希望有一个端点接收(页面、大小)并返回作者的分页列表,如下所示:

public abstract class AuthorDTO implements Serializable {
    public abstract Long authorId();

    public abstract List<Book> books();
}
[
    {
        "authorId": 123,
        "books": [...]
    },
    ...

]

我的第一个想法是创建一个repository调用,它不确定如何获取自定义对象的页面。这在下面是无效的,但是我想做如下的事情。

Page<AuthorDTO> findAllBooksGroupedByAuthorId(Pageable pageable);
wb1gzix0

wb1gzix01#

您的代码似乎表明您正在尝试将类中的外键关系显示为id。jpa实际上并没有这样做。jpa=“java持久性语言”即表示镜像数据库的java类之间的关系。
因此,在数据库中,book表中可能有一个类似于'author\ id'的外键,但在jpa/java端,它将是一个“author”类,而不仅仅是一个long/int。
我希望下面的帮助。我只是在代码的main()上加了它,所以它可能不完美,但我也留下了一些注解。
一旦你有了 Page<Book> 然后您可能希望将其Map到java中的dto。
由于查询是“按作者id获取书籍”,我们可以假设它们都具有相同的作者id…因此没有必要尝试在数据库中获取此投影。
编辑:难道不可能从第三方得到作者的参考吗?
i、 e.我不知道你是如何填充“book”…但是当你从第三方获得“book”时,你能不能看到你是否有一个带有图书“author\u id”的author实体,并且如果一个新的“author”还不存在的话,你就不能用这个id来保存一个新的“author”?
在这种情况下,您可以执行authorrepo并简单地进行如下查询: Page<Author> findAllBy(Pageable page) ==========================================================================
看起来你是在拿一页书,作者id…你真的应该有一个jpa的关系,以表明:

@Entity
    private class Book{

        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private long id;

        @Column(name = "book_name")
        private String name;

        //Technically this could be Many:Many as a book could have 2 authors? If so....@ManyToMany
        //For simplicity (and what you seem to want) Many Books have ONE author.
        @ManyToOne(fetch = FetchType.LAZY)
        private Author author;

    }

    @Entity
    private class Author{

        //ID here - omitted for clarity

        @Column(name = "authors_name")
        String name;

        //The Author has many books.
        // Mapped by shows the bi-direction relationship. You can then do 'Author.getAuthorsBooks()'
        //Lazy means it wont fetch all the books from database/(hibernate wont) when you do AuthorRepo.get()
        //and will only do the `JOIN ON Books where` if you do Author.getAuthorsBooks()
        @OneToMany(fetch = FetchType.LAZY,mappedBy = "author")
        private Set<Book> authorsBooks = new HashSet<>();
    }

    private interface AuthorRepo extends JpaRepository<Author,Long>{
        //Note the JPA syntax.
        Page<Book> findAll(Pageable pageable);
    }

edit:i have 只写在一个空文件…所以它可能需要调整或有打字错误等
如果你不能有一个单独的实体为作者的原因,必须保持你的实体,因为它目前是…我会做2个查询。
我觉得你可以用不同的方法来做。
如果必须使用spring的pageable:
在控制器中获取页面请求并将其放入新的 PageRequest.of(pagenum,size) 并将其输入到下面的页面查询中

List<Long> getPageOfUniqueAuthorIds(Pageable pageable);

这将提供一页作者ID。
然后您需要使用long列表(aithorids)来执行第二个查询。

List<AuthorDTOProjection> getBooksAndAuthorIdsWithAuthorsIdsIn(List<Long> authorIds);
@Entity
    @Table(name="book")
    public class Book {

        @Id
        @GeneratedValue
        private Long id;

        @Column(name="book_name")
        private String bookName;

        @Column(name="author_id")
        private Long authorId;

        //Setters and getters
    }

    private interface BookRepo extends JpaRepository<Book,Long> {

        //The countQuery is required by Spring Paging.
        //Hibernate will need to use the count query when doing paging on a native query.
        @Query(nativeQuery = true,
        value = "SELECT DISTINCT(author_id) FROM book b ",
        countQuery = "SELECT count(*) \n" +
                "FROM (SELECT DISTINCT(author_id) FROM book b) authorIds ")
        List<Long> getPageOfUniqueAuthorIds(Pageable pageable);

        //This is not paged. You want all books with the author IDs from the page query above.
      List<Book> findAllByAuthorIdIn(List<Long> authorIds);
    }

然后必须将实体Map到服务层中的dto。

@Autowired
        BookRepo bookRepo;

        //This would be from the controller method...not declared here...
        Pageable pageableFromController = PageRequest.of(0,10);

        List<Long> pageOfUniqueAuthorIds = bookRepo.getPageOfUniqueAuthorIds(pageableFromController);

        //Get All the books with Author Ids.
        List<Book> books = bookRepo.findAllByAuthorIdIn(pageOfUniqueAuthorIds);

        //Your abstract AuthorDTO.
        abstract class AuthorDTO implements Serializable {
            public abstract Long authorId();

            public abstract List<Book> books();
        }

        //Your Author DTO needs to be implemented so I made a "View".
        @AllArgsConstructor
        class AuthorView extends AuthorDTO{

            private long authorId;
            private List<Book> books;

            @Override
            public Long authorId() {
                return authorId;
            }

            @Override
            public List<Book> books() {
                return books;
            }
        }

        //Get a List of the authorIds in the List<Books>. Could also use the original Page<Long> authorIds...
        //As an author without a book is not possible in your database.
        final List<Long> authorIdsInBooks = books.stream().map(it -> it.authorId).distinct().collect(Collectors.toList());

        //Map the Ids of authors to an Impl of your abstract DTO. Personally I don't see why the AuthorDTO is abstract.
        //I'd have expected just an abstract DTO class called "DTO" or something and then AuthorDTO impl that.
        //But as the way you have it this will work. I guess you may want more impl of the  AuthorDTO so maybe leave the AuthorDTO as abstract.
        //This can be returned to client.
        final List<AuthorView> authorViews = authorIdsInBooks.stream()
                .map(authorId -> new AuthorView(
                        authorId,
                        books.stream().filter(it -> it.authorId.equals(authorId)).collect(Collectors.toList()))
                )
                .collect(Collectors.toList());

相关问题