繁体   English   中英

使用IN运算符进行Set的JPA标准查询 <?> 使用Spring DATA-JPA

[英]JPA Criteria Query with IN operator for Set<?> with Spring DATA-JPA

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

@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)方法过滤我的ApplicantRepository中的某些申请人。

但是,我的问题是我想创建一个规格参数,并接受一个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 Specification中工作。

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

谢谢你的帮助。

我找到了正确的方法,但我的所有尝试都是不好的,因为我在考虑“像对象”而不是在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);


            }
        };
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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