DATAJPA-71 - CriteriaQueries created from derived queries are cached now if possible.
We now create the CriteriaQuery instance for derived queries only once in case the query method does not contain a dynamic sort parameter (either through a plain Sort or via a Pageable).
This commit is contained in:
@@ -22,7 +22,6 @@ import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.repository.query.ParameterAccessor;
|
||||
import org.springframework.data.repository.query.Parameters;
|
||||
import org.springframework.data.repository.query.parser.PartTree;
|
||||
|
||||
@@ -39,13 +38,13 @@ public class JpaCountQueryCreator extends JpaQueryCreator {
|
||||
*
|
||||
* @param tree
|
||||
* @param domainClass
|
||||
* @param accessor
|
||||
* @param parameters
|
||||
* @param em
|
||||
*/
|
||||
public JpaCountQueryCreator(PartTree tree, Class<?> domainClass,
|
||||
ParameterAccessor accessor, Parameters parameters, EntityManager em) {
|
||||
Parameters parameters, EntityManager em) {
|
||||
|
||||
super(tree, domainClass, accessor, parameters, em);
|
||||
super(tree, domainClass, parameters, em);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -66,9 +66,9 @@ public class JpaQueryCreator extends
|
||||
* @param em
|
||||
*/
|
||||
public JpaQueryCreator(PartTree tree, Class<?> domainClass,
|
||||
ParameterAccessor accessor, Parameters parameters, EntityManager em) {
|
||||
Parameters parameters, EntityManager em) {
|
||||
|
||||
super(tree, accessor);
|
||||
super(tree);
|
||||
|
||||
this.builder = em.getCriteriaBuilder();
|
||||
this.query = builder.createQuery().distinct(tree.isDistinct());
|
||||
@@ -80,6 +80,8 @@ public class JpaQueryCreator extends
|
||||
|
||||
|
||||
/**
|
||||
* Returns all {@link ParameterExpression} created when creating the query.
|
||||
*
|
||||
* @return the parameterExpressions
|
||||
*/
|
||||
public List<ParameterExpression<?>> getParameterExpressions() {
|
||||
|
||||
@@ -23,10 +23,11 @@ import javax.persistence.TypedQuery;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.ParameterExpression;
|
||||
|
||||
import org.springframework.data.repository.query.ParameterAccessor;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.repository.query.Parameters;
|
||||
import org.springframework.data.repository.query.ParametersParameterAccessor;
|
||||
import org.springframework.data.repository.query.parser.PartTree;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
@@ -40,6 +41,9 @@ public class PartTreeJpaQuery extends AbstractJpaQuery {
|
||||
private final PartTree tree;
|
||||
private final Parameters parameters;
|
||||
|
||||
private final QueryPreparer query;
|
||||
private final QueryPreparer countQuery;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new {@link PartTreeJpaQuery}.
|
||||
@@ -54,6 +58,9 @@ public class PartTreeJpaQuery extends AbstractJpaQuery {
|
||||
this.domainClass = method.getEntityInformation().getJavaType();
|
||||
this.tree = new PartTree(method.getName(), domainClass);
|
||||
this.parameters = method.getParameters();
|
||||
|
||||
this.query = new QueryPreparer(tree, domainClass, parameters);
|
||||
this.countQuery = new CountQueryPreparer(tree, domainClass, parameters);
|
||||
}
|
||||
|
||||
|
||||
@@ -68,18 +75,7 @@ public class PartTreeJpaQuery extends AbstractJpaQuery {
|
||||
@Override
|
||||
public Query createQuery(Object[] values) {
|
||||
|
||||
ParameterAccessor accessor =
|
||||
new ParametersParameterAccessor(parameters, values);
|
||||
JpaQueryCreator creator =
|
||||
new JpaQueryCreator(tree, domainClass, accessor, parameters,
|
||||
getEntityManager());
|
||||
CriteriaQuery<?> source = creator.createQuery();
|
||||
|
||||
TypedQuery<?> jpaQuery = getEntityManager().createQuery(source);
|
||||
getBinder(values, creator.getParameterExpressions()).bindAndPrepare(
|
||||
jpaQuery);
|
||||
|
||||
return jpaQuery;
|
||||
return query.createQuery(values);
|
||||
}
|
||||
|
||||
|
||||
@@ -92,24 +88,133 @@ public class PartTreeJpaQuery extends AbstractJpaQuery {
|
||||
@Override
|
||||
public Query createCountQuery(Object[] values) {
|
||||
|
||||
ParameterAccessor accessor =
|
||||
new ParametersParameterAccessor(parameters, values);
|
||||
|
||||
JpaCountQueryCreator creator =
|
||||
new JpaCountQueryCreator(tree, domainClass, accessor,
|
||||
parameters, getEntityManager());
|
||||
CriteriaQuery<?> source = creator.createQuery();
|
||||
|
||||
TypedQuery<?> jpaQuery = getEntityManager().createQuery(source);
|
||||
getBinder(values, creator.getParameterExpressions()).bind(jpaQuery);
|
||||
|
||||
return jpaQuery;
|
||||
return countQuery.createQuery(values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query preparer to create {@link CriteriaQuery} instances and potentially
|
||||
* cache them.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
private class QueryPreparer {
|
||||
|
||||
private ParameterBinder getBinder(Object[] values,
|
||||
List<ParameterExpression<?>> expressions) {
|
||||
private CriteriaQuery<?> query;
|
||||
private final JpaQueryCreator creator;
|
||||
|
||||
return new CriteriaQueryParameterBinder(parameters, values, expressions);
|
||||
|
||||
/**
|
||||
* Creates a new {@link QueryPreparer} from the given {@link PartTree},
|
||||
* domain class and {@link Parameters}.
|
||||
*
|
||||
* @param tree
|
||||
* @param domainClass
|
||||
* @param parameters
|
||||
*/
|
||||
public QueryPreparer(PartTree tree, Class<?> domainClass,
|
||||
Parameters parameters) {
|
||||
|
||||
this(new JpaQueryCreator(tree, domainClass, parameters,
|
||||
getEntityManager()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new {@link QueryPreparer} from the given
|
||||
* {@link JpaQueryCreator}.
|
||||
*
|
||||
* @param creator must not be {@literl null}.
|
||||
*/
|
||||
protected QueryPreparer(JpaQueryCreator creator) {
|
||||
|
||||
Assert.notNull(creator);
|
||||
this.creator = creator;
|
||||
this.query = null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new {@link Query} for the given parameter values.
|
||||
*
|
||||
* @param values
|
||||
* @return
|
||||
*/
|
||||
public Query createQuery(Object[] values) {
|
||||
|
||||
if (parameters.potentiallySortsDynamically() || query == null) {
|
||||
query = creator.createQuery(getDynamicSort(values));
|
||||
}
|
||||
|
||||
TypedQuery<?> jpaQuery = getEntityManager().createQuery(query);
|
||||
return invokeBinding(
|
||||
getBinder(values, creator.getParameterExpressions()),
|
||||
jpaQuery);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Invokes parameter binding on the given {@link TypedQuery}.
|
||||
*
|
||||
* @param binder
|
||||
* @param query
|
||||
* @return
|
||||
*/
|
||||
protected Query invokeBinding(ParameterBinder binder,
|
||||
TypedQuery<?> query) {
|
||||
|
||||
return binder.bindAndPrepare(query);
|
||||
}
|
||||
|
||||
|
||||
private ParameterBinder getBinder(Object[] values,
|
||||
List<ParameterExpression<?>> expressions) {
|
||||
|
||||
return new CriteriaQueryParameterBinder(parameters, values,
|
||||
expressions);
|
||||
}
|
||||
|
||||
|
||||
private Sort getDynamicSort(Object[] values) {
|
||||
|
||||
return parameters.hasSortParameter() ? new ParametersParameterAccessor(
|
||||
parameters, values).getSort() : null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Special {@link QueryPreparer} to create count queries.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
private class CountQueryPreparer extends QueryPreparer {
|
||||
|
||||
/**
|
||||
* Creates a new {@link CountQueryPreparer} from the given
|
||||
* {@link PartTree}, domain class and {@link Parameters}. Will use a
|
||||
* {@link JpaCountQueryCreator} to create the query.
|
||||
*
|
||||
* @param tree
|
||||
* @param domainClass
|
||||
* @param parameters
|
||||
*/
|
||||
public CountQueryPreparer(PartTree tree, Class<?> domainClass,
|
||||
Parameters parameters) {
|
||||
|
||||
super(new JpaCountQueryCreator(tree, domainClass, parameters,
|
||||
getEntityManager()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Customizes binding by skipping the pagination.
|
||||
*
|
||||
* @see org.springframework.data.jpa.repository.query.PartTreeJpaQuery.QueryPreparer#invokeBinding(org.springframework.data.jpa.repository.query.ParameterBinder,
|
||||
* javax.persistence.TypedQuery)
|
||||
*/
|
||||
protected Query invokeBinding(ParameterBinder binder,
|
||||
javax.persistence.TypedQuery<?> query) {
|
||||
|
||||
return binder.bind(query);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
<persistence-unit name="hades">
|
||||
<class>org.springframework.data.jpa.domain.AbstractPersistable</class>
|
||||
<class>org.springframework.data.jpa.domain.sample.User</class>
|
||||
<class>org.springframework.data.jpa.domain.sample.SpecialUser</class>
|
||||
<class>org.springframework.data.jpa.domain.sample.Role</class>
|
||||
<class>org.springframework.data.jpa.domain.sample.Account</class>
|
||||
<class>org.springframework.data.jpa.domain.AbstractAuditable</class>
|
||||
|
||||
@@ -4,11 +4,13 @@
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
|
||||
<persistence-unit name="first">
|
||||
<class>org.springframework.data.jpa.domain.sample.User</class>
|
||||
<class>org.springframework.data.jpa.domain.sample.SpecialUser</class>
|
||||
<class>org.springframework.data.jpa.domain.sample.Role</class>
|
||||
<exclude-unlisted-classes>true</exclude-unlisted-classes>
|
||||
</persistence-unit>
|
||||
<persistence-unit name="second">
|
||||
<class>org.springframework.data.jpa.domain.sample.User</class>
|
||||
<class>org.springframework.data.jpa.domain.sample.SpecialUser</class>
|
||||
<class>org.springframework.data.jpa.domain.sample.Role</class>
|
||||
<class>org.springframework.data.jpa.domain.sample.AuditableUser</class>
|
||||
<class>org.springframework.data.jpa.domain.sample.AuditableRole</class>
|
||||
|
||||
Reference in New Issue
Block a user