【问题标题】:JPA Criteria Query with IN operator for Set<?> with Spring DATA-JPAJPA Criteria Query with IN operator for Set<?> with Spring DATA-JPA
【发布时间】:2014-11-27 14:07:43
【问题描述】:

在我的应用程序中,两个实体之间有以下映射:

@Entity
public class Applicant {
     private Integer id;
     ....
     private Set<Document> documents;

     ... Getters and Setters ...

     @OneToMany(fetch = FetchType.LAZY, mappedBy = "applicant", cascade = CascadeType.ALL)
     public Set<Document> getDocuments() {
     return documents;
     }

    public Applicant setDocuments(Set<Document> documents) {
        this.documents = documents;
        return this;
    }
}

和文件:

public class Document {

    private Long id;
    private Applicant applicant;

    ... Getters and Setters ...

    @ManyToOne
    public Applicant getApplicant() {
        return applicant;
    }

    public Document setApplicant(Applicant applicant) {
        this.applicant = applicant;
        return this;
    }
}

我想使用 Spring 数据规范 (org.springframework.data.jpa.domain) 通过 findAll(Spec spec) 方法过滤我的申请人存储库中的一些申请人。

但是,我的问题是我想创建一个规范,以获取参数 a Set 并构建一个规范来过滤未链接到本文档的一个(不是全部)的申请人。

我尝试了不同的方法,但没有一个有效...我不知道我是否忘记了什么。 第一个是使用criteriaBuilder和value方法...

public static Specification<Applicant> applicantHasDoc(final Set<Document> documents) {
        return new Specification<Applicant>() {
            @Override
            public Predicate toPredicate(Root<Applicant> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                /*
                    Problem during parsing the query :
                    select *
                    from
                        applicant applicant0_ cross join document documents1_
                    where
                        applicant0_.id=documents1_.applicant
                        and (. in (? , ?))
                */
                Expression<Set<Document>> documentExpression = root.get(Applicant_.documents);
                return cb.in(documentExpression).value(documents);
        };
    }

这将返回一个 GrammarSQL 异常...您可以在代码中看到 SQL 查询(在申请者字段上进行了简化)。

第二种解决方案是直接在申请人的ROOT上使用元模型和In:

public static Specification<Applicant> applicantHasDoc(final Set<Document> documents) {
        return new Specification<Applicant>() {
            @Override
            public Predicate toPredicate(Root<Applicant> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                /*        
                    Error with this type of criteria : Parameter value [com.myapp.entity.Document@1b275eae] did not match expected type [java.util.Set (n/a)]
                */
                    return root.get(Applicant_.documents).in(documents);
            }
        };
    }

我已经在代码中添加了每个解决方案的结果......但它们都不起作用。

本规范的主要目的是与类似的其他人一起使用:

List<Applicant> applicants = findAll(where(applicantHasDoc(documents).and(otherSpec(tags)).and(anotherSpec(mobilities), page);

所以我只能在 Spring Data JPA 规范中工作。

其他信息:我正在使用 H2 数据库。

感谢您的帮助。

【问题讨论】:

    标签: java spring jpa spring-data-jpa criteriaquery


    【解决方案1】:

    我找到了正确的方法,但我所有的尝试都很糟糕,因为我在想“像对象”而不是在 SQL 中......但是 CriteriaQuery 是构建 SQL 查询的“对象包装器”。

    所以,我用 SQL 编写了我想要的查询并找到了解决方案:

    我想要的 SQL 是:

    select * 
    from applicant applicant0_ inner join document documents1_ on applicant0_.id=documents1_.applicant where documents1_.id in (? , ?)
    

    所以我的谓词似乎如下:

       public static Specification<Applicant> applicantHasDoc(final Set<Document> documents) {
            return new Specification<Applicant>() {
                @Override
                public Predicate toPredicate(Root<Applicant> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                    SetJoin<Applicant, Document> documentApplicantJoin = root.join(Applicant_.documents);
                    return documentApplicantJoin.in(documents);
    
    
                }
            };
        }
    

    【讨论】:

    • 另外,在这样做join 时,您可能需要设置 distinct select query.distinct(true)
    猜你喜欢
    • 2017-08-21
    • 2020-02-22
    • 2016-12-22
    • 1970-01-01
    • 2013-11-02
    • 2011-04-30
    • 2015-06-28
    • 2016-03-09
    • 2011-02-10
    相关资源
    最近更新 更多