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.
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.
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...
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.
The second solution was to use metamodel and In directly on the ROOT of applicant :
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.
Other information : I'm using H2 Database.
Thanks for your help.