简体   繁体   中英

How to add a count field in spring data jpa and spring boot with join

I work on a rest library project with Spring boot and spring data. I have an entity Book that has a collection of BookCopies.

@Entity
@Getter
@Setter
@NoArgsConstructor
public class Book {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String isbn;
    @NotNull
    private String title;

    @JsonIgnore
    @OneToMany(mappedBy = "book", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<BookCopy> copyList = new ArrayList<>();

...

@Entity
@Getter
@Setter
@Builder
@AllArgsConstructor
public class BookCopy {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String barcode;
    private String editor;
    private boolean available = true;

    @ManyToOne(fetch = FetchType.LAZY)
    private Book book;
...

And I would like to perform a request that gives me all the books and the number of copies that are available. I have no problem to perform it in standard sql:

select book.*, count(book_copy.id) as nb_copies from book
inner join book_copy on book.id = book_copy.book_id
where book.title like '%:title%' 
and book_copy.available = true
group by book.id

But I can't manage to make it work in my project. I thought I could do it with jpql, but when I try to join the entity bookCopy, intellij doesn't make any autocompletion, which makes me suspect that there is a configuration problem. If I try "run query in console" it tells me "no runner found", even if I set up the database in intellij. I also tried to do it with native query, but it doesn't work either.

I managed to get a result but I think with a wrong method:

@Override
    public List<Book> findByTitle(String title) {
        List<Book> bookList = bookRepository.findByTitleLike("%"+title+"%");
        for(Book book:bookList){
            book.setCopyList(bookCopyRepository.findAllInBookWhereAvailable(book.getId(), true));
        }
        return bookList;
    }

Which will start a query for each book to get the copylist. So I'm out of ideas and I can't get much clear infos about it. Thanks!

The following JPQL should return the same data set as your native SQL query:

select b, count(c) from Book b
join b.copyList c
where b.title like :title and c.available
group by b

Java code:

        String title = ...;
        final List result = em.createQuery("select b, count(c) from Book b" +
                " join b.copyList c " +
                " where b.title like :title and c.available " +
                " group by b ")
                .setParameter("title", title)
                .getResultList();
        for (Object res : result) {
            Object[]  row = (Object[]) res;
            System.out.println("Book: " + row[0]);
            System.out.println("BookCopy CNT: " + row[1]);
        }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM