如何构建条件查询以获取列表中包含某些特定对象的所有对象

时间:2019-04-24 11:14:48

标签: java spring criteria specifications criteria-api

我有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

} 

我需要构建一个条件查询来查找所有具有与标签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.Abs​​tractFromImpl.joinList(AbstractFromImpl.java:497)〜[hibernate-entitymanager-4.3.11.Final.jar:4.3.11.Final]     在org.hibernate.jpa.criteria.path.Abs​​tractFromImpl.joinList(AbstractFromImpl.java:484)〜[hibernate-entitymanager-4.3.11.Final.jar:4.3.11.Final]

2 个答案:

答案 0 :(得分:0)

可以如下构建这样的查询:

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();

答案 1 :(得分:0)

好吧,所以我不是循环搜索所有标签,而是循环进入id并为每个id生成不同的规范:

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);
        };
    }