Конвертировать указанный запрос c в запрос JPQL или Criteria Builder - PullRequest
0 голосов
/ 24 февраля 2020

Вот код для 2 сущностей (он генерирует три таблицы в базе данных). Book сущность:

@Entity
public class Book {
    @Id
    private long id;

    private String name;

    @ManyToMany
    private List<Author> authors;
}

Author сущность:

@Entity
public class Author {
    @Id
    private long id;

    @Column(unique=true)
    private String name;
}

Я пытаюсь найти книги по списку авторов. Вот запрос sql:

select book.id, ARRAY_AGG(author.name)
from book 
join book_authors ba on book.id=ba.book_id 
join author on ba.authors_id=author.id
group by book.id
having  ARRAY_AGG(distinct author.name order by author.name)=ARRAY['a1', 'a2']::varchar[]

['a1', 'a2'] - список авторов книг, его необходимо передать в качестве параметра. Идея состоит в том, чтобы объединить авторов и затем сравнить их со списком переданных параметров.

Как переписать этот SQL -запрос в запрос JPQL или CriteriaBuilder?

Ответы [ 2 ]

1 голос
/ 25 февраля 2020

Если точное совпадение необходимо, вы можете использовать Specification, например,

public class BookSpecifications {
        public static Specification<Book> byAuthorsNames(List<String> names) {
            return (root, query, builder) -> {
                Join<Book, Author> author = root.join("authors", JoinType.LEFT);

                Predicate predicate = builder.conjunction;
                for(String name : names) {
                    Predicate namePredicate = builder.and(author.get("name"), name);
                    predicate = builder.and(predicate, namePredicate);
                }

                return predicate;
            }
        }
}

BookRepository необходимо расширить JpaSpecificationExecutor.

Использование:

BookRepository repository;

public List<Book> findByAuthorsNames(List<String> names) {
    return repository.findAll(BookSpecifications.byAuthorsNames(names));
}
1 голос
/ 25 февраля 2020
@Query("select distinct b from Book b join b.authors a where a.name in(:names)")
List<Book> findByAuthorsNames(@Param("names") List<String> names)

Если вы хотите получить b.authors, используйте join fetch вместо join

...