spring-projects / spring-data-jpa

Simplifies the development of creating a JPA-based data access layer.
https://spring.io/projects/spring-data-jpa/
Apache License 2.0
3.01k stars 1.42k forks source link

Specification.toPredicate(…) will be called twice when calling findAll(spec, pageable) [DATAJPA-404] #812

Closed spring-projects-issues closed 5 years ago

spring-projects-issues commented 11 years ago

grf110 opened DATAJPA-404 and commented

Use findAll(Specification<T> spec, Pageable pageable). Problem: will be call method Specification.toPredicate(…) twice.

Reason: method findAll(spec, pageable) have call org.springframework.data.jpa.repository.support.SimpleJpaRepository#readPage and org.springframework.data.jpa.repository.support.SimpleJpaRepository#getQuery

they all call

org.springframework.data.jpa.repository.support.SimpleJpaRepository#applySpecificationToCriteria so

Predicate predicate = spec.toPredicate(root, query, builder);

Run twice.


Affects: 1.4.1

spring-projects-issues commented 11 years ago

Oliver Drotbohm commented

This is correct I think. We need to execute two queries: one to retrieve the results and an additional count query to find out how many pages there are in total. Thus, the Specification instance has to be applied to both of them, hence ….toPredicate(…) is called twice.

What is the actual problem you are seeing?

spring-projects-issues commented 11 years ago

grf110 commented

Look my java code

public class CriteriaSearch {
public List<SearchEntity> searchEntitys = new ArrayList<SearchEntity>();
private List<Predicate> predicates = new ArrayList<Predicate>();;
public <T> Specification<T> predicateBuild() {
return new Specification<T>() {
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
for (SearchEntity se : searchEntitys) {
String[] names = StringUtils.split(se.getFieldName(), ".");
Path expression = root.get(names[0]);
for (int i = 1; i < names.length; i++)
{ expression = expression.get(names[i]); }
predicates.add((Predicate) ReflectionUtils.invokeMethod(se.getOperator().getMethod(), builder, expression, se.getValue().toString()));
}
return builder.and(predicates.toArray(new Predicate[predicates.size()]));
}
};
}
}

predicates value will be double. I may be set predicates=null resolve this problem

spring-projects-issues commented 11 years ago

Oliver Drotbohm commented

Specifications need to be side effect free, which in your case they aren't

spring-projects-issues commented 5 years ago

Jens Schauder commented

Batch closing resolved issue without a fix version and a resolution indicating that there is nothing to release (Won't fix, Invalid ...)

valerarenny commented 2 years ago

Specification is returning two sets of results with diferent criteria

Ixiodor commented 5 months ago

Hi! My 5c to that too: My specification get executed twice too, so I get

Already registered a copy: SqmEntityValuedSimplePath ...

For some reason, it's a problem only on a specific class and I can't get why(To be specific, it's a problem when IN has more values inside )