简体   繁体   English

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

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

In my application, I have the following mapping between two entities : 在我的应用程序中,两个实体之间具有以下映射:

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

And Document : 和文件:

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

I want to use the Spring Data Specification (org.springframework.data.jpa.domain) to filter some applicant in my ApplicantRepository with the findAll(Spec spec) method. 我想使用Spring数据规范(org.springframework.data.jpa.domain)通过findAll(Spec spec)方法过滤我的ApplicantRepository中的某些申请人。

But, my problem is I want to create a specification witch take in parameters a Set and build a specification to filter the applicant who are not linked to one (not all) of this document. 但是,我的问题是我想创建一个规格参数,并接受一个Set参数,并建立一个规格以过滤未链接到该文档中一个 (不是全部)的申请人。

I've tried different things but none of them work... I don't know if I am forgetting something. 我尝试了不同的方法,但是它们都不起作用...我不知道我是否忘记了什么。 The first one was to use the criteriaBuilder and value method... 第一个是使用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);
        };
    }

That's returning an GrammarSQL exception... you can see the SQL query (simplified on the applicant fields) in the code. 那将返回一个GrammarSQL异常...您可以在代码中看到SQL查询(在申请人字段中已简化)。

The second solution was to use metamodel and In directly on the ROOT of applicant : 第二种解决方案是直接在申请人的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);
            }
        };
    }

I have add in the code the result of each solution... and none of them work. 我在代码中添加了每个解决方案的结果...但它们都不起作用。

The main purpose of this Specification is to be used with others like that : 本规范的主要目的是与其他类似的对象一起使用:

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

So I can only work inside a Spring Data JPA Specification. 所以我只能在Spring Data JPA Specification中工作。

Other information : I'm using H2 Database. 其他信息:我正在使用H2数据库。

Thanks for your help. 谢谢你的帮助。

I find the right way to do that, and all my attempt was bad because I was thinking "like object" and not in SQL... but CriteriaQuery is a "object wrapper" to build SQL query. 我找到了正确的方法,但我的所有尝试都是不好的,因为我在考虑“像对象”而不是在SQL中……但是CriteriaQuery是构建SQL查询的“对象包装器”。

So, I wrote the query I want in SQL and I found the solution : 所以,我用SQL编写了我想要的查询,然后找到了解决方案:

What I want in SQL was : 我想要的SQL是:

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

So my predicate seems to be the following : 所以我的谓词似乎如下:

   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