Как создать критерий запроса, чтобы получить все объекты, которые содержат определенные конкретные объекты в списке - PullRequest
0 голосов
/ 24 апреля 2019

У меня есть 2 класса, один отец, у которого много детей, например:

Class Person {
    @ManyToMany
    @JoinTable(name = "person_tag",
            joinColumns = {@JoinColumn(name = "person_id", 
            referencedColumnName = "id")},
            inverseJoinColumns = {@JoinColumn(name = "tag_id", 
            referencedColumnName = "id")})    
    List<Tag> tags;

}


Class Tag {

    Long id

} 

Мне нужно создать критерий запроса, чтобы найти всех людей, у которых есть теги, которые соответствуют списку идентификаторов тегов.

Я сохраняю это отношение в новой таблице с двумя столбцами: person_id tag_id

Я реализовал следующее решение:

  private Specification<Person> generatePersonIdsSpecification(List<Long> ids) {
        return (root, query, cb) -> {
            Subquery<Person> sq = query.subquery(Person.class);
            Root<Person> person = sq.from(Person.class);
            ListJoin<Person, Tag> tagJoin = person.joinList("tags");
            sq.select(person).distinct(true).where(tagJoin.get("id").in(ids));
            return cb.in(root).value(sq);
        };
    }

Но я получаю:

Причина: java.lang.IllegalArgumentException: Запрошенный атрибут не был списком в org.hibernate.jpa.criteria.path.AbstractFromImpl.joinList (AbstractFromImpl.java:497) ~ [hibernate-entitymanager-4.3.11.Final.jar: 4.3.11.Final] at org.hibernate.jpa.criteria.path.AbstractFromImpl.joinList (AbstractFromImpl.java:484) ~ [hibernate-entitymanager-4.3.11.Final.jar: 4.3.11.Final]

Ответы [ 2 ]

0 голосов
/ 24 апреля 2019

Хорошо, так что вместо поиска всех тегов вместе, я просто зацикливаюсь на идентификаторы и генерирую различные спецификации для каждого идентификатора:

private Specification<Person> generateByTagIdSpecification(Long id) {
        return (root, query, cb) -> {
            Subquery<Person> sq = query.subquery(Person.class);
            Root<Person> person = sq.from(Person.class);
            Join<Person, Tag> join = person.join("tags");
            sq.select(person).distinct(true).where(cb.equal(join.get("id"), id));
            return cb.in(root).value(sq);
        };
    }
0 голосов
/ 24 апреля 2019

Такой запрос можно построить следующим образом:

List<Long> someTagIds ...

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Person> query = cb.createQuery(Person.class);

Root<Person> person = query.from(Person.class);
ListJoin<Person, Tag> tagJoin = person.joinList("tags");

query.select(person).distinct(true)
     .where(tagJoin.get("id").in(someTagIds));
List<Person> result = em.createQuery(query).getResultList();
...