Skip to content

Replace derived CriteriaQuery with String-based queries #3653

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa-parent</artifactId>
<version>4.0.0-SNAPSHOT</version>
<version>4.0.0-GH-3588-SNAPSHOT</version>
<packaging>pom</packaging>

<name>Spring Data JPA Parent</name>
Expand Down
4 changes: 2 additions & 2 deletions spring-data-envers/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-envers</artifactId>
<version>4.0.0-SNAPSHOT</version>
<version>4.0.0-GH-3588-SNAPSHOT</version>

<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa-parent</artifactId>
<version>4.0.0-SNAPSHOT</version>
<version>4.0.0-GH-3588-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
2 changes: 1 addition & 1 deletion spring-data-jpa-distribution/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa-parent</artifactId>
<version>4.0.0-SNAPSHOT</version>
<version>4.0.0-GH-3588-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
4 changes: 2 additions & 2 deletions spring-data-jpa/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>4.0.0-SNAPSHOT</version>
<version>4.0.0-GH-3588-SNAPSHOT</version>

<name>Spring Data JPA</name>
<description>Spring Data module for JPA repositories.</description>
Expand All @@ -15,7 +15,7 @@
<parent>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa-parent</artifactId>
<version>4.0.0-SNAPSHOT</version>
<version>4.0.0-GH-3588-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -235,8 +235,8 @@ private Query applyLockMode(Query query, JpaQueryMethod method) {
return lockModeType == null ? query : query.setLockMode(lockModeType);
}

protected ParameterBinder createBinder() {
return ParameterBinderFactory.createBinder(getQueryMethod().getParameters());
ParameterBinder createBinder() {
return ParameterBinderFactory.createBinder(getQueryMethod().getParameters(), false);
}

protected Query createQuery(JpaParametersParameterAccessor parameters) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ abstract class AbstractStringBasedJpaQuery extends AbstractJpaQuery {
private final DeclaredQuery query;
private final Lazy<DeclaredQuery> countQuery;
private final ValueExpressionDelegate valueExpressionDelegate;
private final QueryParameterSetter.QueryMetadataCache metadataCache = new QueryParameterSetter.QueryMetadataCache();
private final QueryRewriter queryRewriter;
private final QuerySortRewriter querySortRewriter;
private final Lazy<ParameterBinder> countParameterBinder;
Expand Down Expand Up @@ -121,11 +120,9 @@ public Query doCreateQuery(JpaParametersParameterAccessor accessor) {

Query query = createJpaQuery(sortedQueryString, sort, accessor.getPageable(), processor.getReturnedType());

QueryParameterSetter.QueryMetadata metadata = metadataCache.getMetadata(sortedQueryString, query);

// it is ok to reuse the binding contained in the ParameterBinder although we create a new query String because the
// parameters in the query do not change.
return parameterBinder.get().bindAndPrepare(query, metadata, accessor);
return parameterBinder.get().bindAndPrepare(query, accessor);
}

String getSortedQueryString(Sort sort) {
Expand All @@ -152,9 +149,8 @@ protected Query doCreateCountQuery(JpaParametersParameterAccessor accessor) {
? em.createNativeQuery(queryString) //
: em.createQuery(queryString, Long.class);

QueryParameterSetter.QueryMetadata metadata = metadataCache.getMetadata(queryString, query);

countParameterBinder.get().bind(metadata.withQuery(query), accessor, QueryParameterSetter.ErrorHandling.LENIENT);
countParameterBinder.get().bind(new QueryParameterSetter.BindableQuery(query), accessor,
QueryParameterSetter.ErrorHandling.LENIENT);

return query;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class HibernateJpaParametersParameterAccessor extends JpaParametersParameterAcce
* @param values must not be {@literal null}.
* @param em must not be {@literal null}.
*/
HibernateJpaParametersParameterAccessor(Parameters<?, ?> parameters, Object[] values, EntityManager em) {
HibernateJpaParametersParameterAccessor(JpaParameters parameters, Object[] values, EntityManager em) {

super(parameters, values);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,12 @@
*/
package org.springframework.data.jpa.repository.query;

import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Expression;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import jakarta.persistence.EntityManager;

import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.support.JpqlQueryTemplates;
import org.springframework.data.repository.query.ReturnedType;
import org.springframework.data.repository.query.parser.PartTree;
import org.springframework.lang.Nullable;

/**
* Special {@link JpaQueryCreator} that creates a count projecting query.
Expand All @@ -36,41 +32,35 @@
*/
public class JpaCountQueryCreator extends JpaQueryCreator {

private boolean distinct;
private final boolean distinct;
private final ReturnedType returnedType;

/**
* Creates a new {@link JpaCountQueryCreator}.
* Creates a new {@link JpaCountQueryCreator}
*
* @param tree
* @param type
* @param builder
* @param returnedType
* @param provider
* @param templates
* @param em
*/
public JpaCountQueryCreator(PartTree tree, ReturnedType type, CriteriaBuilder builder,
ParameterMetadataProvider provider) {
public JpaCountQueryCreator(PartTree tree, ReturnedType returnedType, ParameterMetadataProvider provider,
JpqlQueryTemplates templates, EntityManager em) {

super(tree, type, builder, provider);
super(tree, returnedType, provider, templates, em);

this.distinct = tree.isDistinct();
this.returnedType = returnedType;
}

@Override
protected CriteriaQuery<? extends Object> createCriteriaQuery(CriteriaBuilder builder, ReturnedType type) {
protected JpqlQueryBuilder.Select buildQuery(Sort sort) {

return builder.createQuery(Long.class);
}

@Override
@SuppressWarnings("unchecked")
protected CriteriaQuery<? extends Object> complete(@Nullable Predicate predicate, Sort sort,
CriteriaQuery<? extends Object> query, CriteriaBuilder builder, Root<?> root) {

CriteriaQuery<? extends Object> select = query.select(getCountQuery(query, builder, root));
return predicate == null ? select : select.where(predicate);
}
JpqlQueryBuilder.SelectStep selectStep = JpqlQueryBuilder.selectFrom(returnedType.getDomainType());
if (this.distinct) {
selectStep = selectStep.distinct();
}

@SuppressWarnings("rawtypes")
private Expression getCountQuery(CriteriaQuery<?> query, CriteriaBuilder builder, Root<?> root) {
return distinct ? builder.countDistinct(root) : builder.count(root);
return selectStep.count();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,19 @@
*/
package org.springframework.data.jpa.repository.query;

import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import jakarta.persistence.EntityManager;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;

import org.springframework.data.domain.KeysetScrollPosition;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.JpqlQueryTemplates;
import org.springframework.data.repository.query.ReturnedType;
import org.springframework.data.repository.query.parser.PartTree;
import org.springframework.lang.Nullable;
Expand All @@ -41,35 +42,67 @@ class JpaKeysetScrollQueryCreator extends JpaQueryCreator {

private final JpaEntityInformation<?, ?> entityInformation;
private final KeysetScrollPosition scrollPosition;
private final ParameterMetadataProvider provider;
private final List<ParameterBinding> syntheticBindings = new ArrayList<>();

public JpaKeysetScrollQueryCreator(PartTree tree, ReturnedType type, CriteriaBuilder builder,
ParameterMetadataProvider provider, JpaEntityInformation<?, ?> entityInformation,
KeysetScrollPosition scrollPosition) {
public JpaKeysetScrollQueryCreator(PartTree tree, ReturnedType type, ParameterMetadataProvider provider,
JpqlQueryTemplates templates, JpaEntityInformation<?, ?> entityInformation, KeysetScrollPosition scrollPosition,
EntityManager em) {

super(tree, type, builder, provider);
super(tree, type, provider, templates, em);

this.entityInformation = entityInformation;
this.scrollPosition = scrollPosition;
this.provider = provider;
}

@Override
protected CriteriaQuery<?> complete(@Nullable Predicate predicate, Sort sort, CriteriaQuery<?> query,
CriteriaBuilder builder, Root<?> root) {
public List<ParameterBinding> getBindings() {

List<ParameterBinding> partTreeBindings = super.getBindings();
List<ParameterBinding> bindings = new ArrayList<>(partTreeBindings.size() + this.syntheticBindings.size());
bindings.addAll(partTreeBindings);
bindings.addAll(this.syntheticBindings);

return bindings;
}

@Override
protected JpqlQueryBuilder.AbstractJpqlQuery createQuery(@Nullable JpqlQueryBuilder.Predicate predicate, Sort sort) {

KeysetScrollSpecification<Object> keysetSpec = new KeysetScrollSpecification<>(scrollPosition, sort,
entityInformation);
Predicate keysetPredicate = keysetSpec.createPredicate(root, builder);

CriteriaQuery<?> queryToUse = super.complete(predicate, keysetSpec.sort(), query, builder, root);
JpqlQueryBuilder.Select query = buildQuery(keysetSpec.sort());

AtomicInteger counter = new AtomicInteger(provider.getBindings().size());
JpqlQueryBuilder.Predicate keysetPredicate = keysetSpec.createJpqlPredicate(getFrom(), getEntity(), value -> {

syntheticBindings.add(provider.nextSynthetic(value, scrollPosition));
return placeholder(counter.incrementAndGet());
});
JpqlQueryBuilder.Predicate predicateToUse = getPredicate(predicate, keysetPredicate);

if (predicateToUse != null) {
return query.where(predicateToUse);
}

return query;
}

@Nullable
private static JpqlQueryBuilder.Predicate getPredicate(@Nullable JpqlQueryBuilder.Predicate predicate,
@Nullable JpqlQueryBuilder.Predicate keysetPredicate) {

if (keysetPredicate != null) {
if (queryToUse.getRestriction() != null) {
return queryToUse.where(builder.and(queryToUse.getRestriction(), keysetPredicate));
if (predicate != null) {
return predicate.nest().and(keysetPredicate.nest());
} else {
return keysetPredicate;
}
return queryToUse.where(keysetPredicate);
}

return queryToUse;
return predicate;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ protected JpaParameters(ParametersSource parametersSource,
super(parametersSource, parameterFactory);
}

private JpaParameters(List<JpaParameter> parameters) {
JpaParameters(List<JpaParameter> parameters) {
super(parameters);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,21 @@
*/
public class JpaParametersParameterAccessor extends ParametersParameterAccessor {

private final JpaParameters parameters;

/**
* Creates a new {@link ParametersParameterAccessor}.
*
* @param parameters must not be {@literal null}.
* @param values must not be {@literal null}.
*/
public JpaParametersParameterAccessor(Parameters<?, ?> parameters, Object[] values) {
public JpaParametersParameterAccessor(JpaParameters parameters, Object[] values) {
super(parameters, values);
this.parameters = parameters;
}

public JpaParameters getParameters() {
return parameters;
}

@Nullable
Expand Down
Loading