Polishing.
Rename Projector to EntityGraphFactory. Remove QuerydslProjector and TypedQueryProjector. Remove MappingContext creation. See #2329 Original pull request: #2345.
This commit is contained in:
committed by
Greg L. Turnquist
parent
83ba970465
commit
d637ce35df
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.jpa.repository.support;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.EntityGraph;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.Subgraph;
|
||||
|
||||
import org.springframework.data.mapping.PropertyPath;
|
||||
|
||||
/**
|
||||
* Factory class to create an {@link EntityGraph} from a collection of property paths.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @since 2.6
|
||||
*/
|
||||
abstract class EntityGraphFactory {
|
||||
|
||||
public static final String HINT = "javax.persistence.fetchgraph";
|
||||
|
||||
/**
|
||||
* Create an {@link EntityGraph} from a collection of properties.
|
||||
*
|
||||
* @param domainType
|
||||
* @param properties
|
||||
*/
|
||||
public static <T> EntityGraph<T> create(EntityManager entityManager, Class<T> domainType, Set<String> properties) {
|
||||
|
||||
EntityGraph<T> entityGraph = entityManager.createEntityGraph(domainType);
|
||||
|
||||
for (String property : properties) {
|
||||
|
||||
Subgraph<Object> current = null;
|
||||
|
||||
for (PropertyPath path : PropertyPath.from(property, domainType)) {
|
||||
|
||||
if (path.hasNext()) {
|
||||
current = current == null ? entityGraph.addSubgraph(path.getSegment())
|
||||
: current.addSubgraph(path.getSegment());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (current == null) {
|
||||
entityGraph.addAttributeNodes(path.getSegment());
|
||||
} else {
|
||||
current.addAttributeNodes(path.getSegment());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return entityGraph;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -32,9 +32,6 @@ import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.jpa.repository.query.EscapeCharacter;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery;
|
||||
import org.springframework.data.support.PageableExecutionUtils;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -58,34 +55,29 @@ class FetchableFluentQueryByExample<S, R> extends FluentQuerySupport<S, R> imple
|
||||
private final Function<Example<S>, Boolean> existsOperation;
|
||||
private final EntityManager entityManager;
|
||||
private final EscapeCharacter escapeCharacter;
|
||||
private final Projector<TypedQuery<?>> projector;
|
||||
|
||||
public FetchableFluentQueryByExample(Example<S> example, Function<Sort, TypedQuery<S>> finder,
|
||||
Function<Example<S>, Long> countOperation, Function<Example<S>, Boolean> existsOperation,
|
||||
MappingContext<? extends PersistentEntity<?, ?>, ? extends PersistentProperty<?>> context,
|
||||
EntityManager entityManager, EscapeCharacter escapeCharacter) {
|
||||
this(example, example.getProbeType(), (Class<R>) example.getProbeType(), Sort.unsorted(), Collections.emptySet(),
|
||||
finder, countOperation, existsOperation, context, entityManager, escapeCharacter,
|
||||
new TypedQueryProjector(entityManager));
|
||||
finder, countOperation, existsOperation, entityManager, escapeCharacter);
|
||||
}
|
||||
|
||||
private FetchableFluentQueryByExample(Example<S> example, Class<S> entityType, Class<R> returnType, Sort sort,
|
||||
Collection<String> properties, Function<Sort, TypedQuery<S>> finder, Function<Example<S>, Long> countOperation,
|
||||
Function<Example<S>, Boolean> existsOperation,
|
||||
MappingContext<? extends PersistentEntity<?, ?>, ? extends PersistentProperty<?>> context,
|
||||
EntityManager entityManager, EscapeCharacter escapeCharacter, Projector<TypedQuery<?>> projector) {
|
||||
EntityManager entityManager, EscapeCharacter escapeCharacter) {
|
||||
|
||||
super(returnType, sort, properties, context, entityType);
|
||||
super(returnType, sort, properties, entityType);
|
||||
this.example = example;
|
||||
this.finder = finder;
|
||||
this.countOperation = countOperation;
|
||||
this.existsOperation = existsOperation;
|
||||
this.entityManager = entityManager;
|
||||
this.escapeCharacter = escapeCharacter;
|
||||
this.projector = projector;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#sortBy(org.springframework.data.domain.Sort)
|
||||
*/
|
||||
@@ -95,11 +87,10 @@ class FetchableFluentQueryByExample<S, R> extends FluentQuerySupport<S, R> imple
|
||||
Assert.notNull(sort, "Sort must not be null!");
|
||||
|
||||
return new FetchableFluentQueryByExample<>(example, entityType, resultType, sort.and(sort), properties, finder,
|
||||
countOperation, existsOperation, context, entityManager, escapeCharacter,
|
||||
new TypedQueryProjector(entityManager));
|
||||
countOperation, existsOperation, entityManager, escapeCharacter);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#as(java.lang.Class)
|
||||
*/
|
||||
@@ -112,11 +103,10 @@ class FetchableFluentQueryByExample<S, R> extends FluentQuerySupport<S, R> imple
|
||||
}
|
||||
|
||||
return new FetchableFluentQueryByExample<>(example, entityType, resultType, sort, properties, finder,
|
||||
countOperation, existsOperation, context, entityManager, escapeCharacter,
|
||||
new TypedQueryProjector(entityManager));
|
||||
countOperation, existsOperation, entityManager, escapeCharacter);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#project(java.util.Collection)
|
||||
*/
|
||||
@@ -124,11 +114,10 @@ class FetchableFluentQueryByExample<S, R> extends FluentQuerySupport<S, R> imple
|
||||
public FetchableFluentQuery<R> project(Collection<String> properties) {
|
||||
|
||||
return new FetchableFluentQueryByExample<>(example, entityType, resultType, sort, mergeProperties(properties),
|
||||
finder, countOperation, existsOperation, context, entityManager, escapeCharacter,
|
||||
new TypedQueryProjector(entityManager));
|
||||
finder, countOperation, existsOperation, entityManager, escapeCharacter);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#oneValue()
|
||||
*/
|
||||
@@ -147,7 +136,7 @@ class FetchableFluentQueryByExample<S, R> extends FluentQuerySupport<S, R> imple
|
||||
return results.isEmpty() ? null : getConversionFunction().apply(results.get(0));
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#firstValue()
|
||||
*/
|
||||
@@ -162,7 +151,7 @@ class FetchableFluentQueryByExample<S, R> extends FluentQuerySupport<S, R> imple
|
||||
return results.isEmpty() ? null : getConversionFunction().apply(results.get(0));
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#all()
|
||||
*/
|
||||
@@ -174,7 +163,7 @@ class FetchableFluentQueryByExample<S, R> extends FluentQuerySupport<S, R> imple
|
||||
return convert(resultList);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#page(org.springframework.data.domain.Pageable)
|
||||
*/
|
||||
@@ -183,7 +172,7 @@ class FetchableFluentQueryByExample<S, R> extends FluentQuerySupport<S, R> imple
|
||||
return pageable.isUnpaged() ? new PageImpl<>(all()) : readPage(pageable);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#stream()
|
||||
*/
|
||||
@@ -195,7 +184,7 @@ class FetchableFluentQueryByExample<S, R> extends FluentQuerySupport<S, R> imple
|
||||
.map(getConversionFunction());
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#count()
|
||||
*/
|
||||
@@ -204,7 +193,7 @@ class FetchableFluentQueryByExample<S, R> extends FluentQuerySupport<S, R> imple
|
||||
return countOperation.apply(example);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#exists()
|
||||
*/
|
||||
@@ -230,7 +219,10 @@ class FetchableFluentQueryByExample<S, R> extends FluentQuerySupport<S, R> imple
|
||||
private TypedQuery<S> createSortedAndProjectedQuery() {
|
||||
|
||||
TypedQuery<S> query = finder.apply(sort);
|
||||
projector.apply(entityType, query, properties);
|
||||
|
||||
if (!properties.isEmpty()) {
|
||||
query.setHint(EntityGraphFactory.HINT, EntityGraphFactory.create(entityManager, entityType, properties));
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
@@ -23,14 +23,13 @@ import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery;
|
||||
import org.springframework.data.support.PageableExecutionUtils;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -56,34 +55,32 @@ class FetchableFluentQueryByPredicate<S, R> extends FluentQuerySupport<S, R> imp
|
||||
private final BiFunction<Sort, Pageable, AbstractJPAQuery<?, ?>> pagedFinder;
|
||||
private final Function<Predicate, Long> countOperation;
|
||||
private final Function<Predicate, Boolean> existsOperation;
|
||||
private final Projector<AbstractJPAQuery<?, ?>> projector;
|
||||
private final EntityManager entityManager;
|
||||
|
||||
public FetchableFluentQueryByPredicate(Predicate predicate, Class<S> entityType,
|
||||
Function<Sort, AbstractJPAQuery<?, ?>> finder, BiFunction<Sort, Pageable, AbstractJPAQuery<?, ?>> pagedFinder,
|
||||
Function<Predicate, Long> countOperation, Function<Predicate, Boolean> existsOperation,
|
||||
MappingContext<? extends PersistentEntity<?, ?>, ? extends PersistentProperty<?>> context,
|
||||
Projector<AbstractJPAQuery<?, ?>> projector) {
|
||||
EntityManager entityManager) {
|
||||
this(predicate, entityType, (Class<R>) entityType, Sort.unsorted(), Collections.emptySet(), finder, pagedFinder,
|
||||
countOperation, existsOperation, context, projector);
|
||||
countOperation, existsOperation, entityManager);
|
||||
}
|
||||
|
||||
private FetchableFluentQueryByPredicate(Predicate predicate, Class<S> entityType, Class<R> resultType, Sort sort,
|
||||
Collection<String> properties, Function<Sort, AbstractJPAQuery<?, ?>> finder,
|
||||
BiFunction<Sort, Pageable, AbstractJPAQuery<?, ?>> pagedFinder, Function<Predicate, Long> countOperation,
|
||||
Function<Predicate, Boolean> existsOperation,
|
||||
MappingContext<? extends PersistentEntity<?, ?>, ? extends PersistentProperty<?>> context,
|
||||
Projector<AbstractJPAQuery<?, ?>> projector) {
|
||||
EntityManager entityManager) {
|
||||
|
||||
super(resultType, sort, properties, context, entityType);
|
||||
super(resultType, sort, properties, entityType);
|
||||
this.predicate = predicate;
|
||||
this.finder = finder;
|
||||
this.pagedFinder = pagedFinder;
|
||||
this.countOperation = countOperation;
|
||||
this.existsOperation = existsOperation;
|
||||
this.projector = projector;
|
||||
this.entityManager = entityManager;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#sortBy(org.springframework.data.domain.Sort)
|
||||
*/
|
||||
@@ -93,10 +90,10 @@ class FetchableFluentQueryByPredicate<S, R> extends FluentQuerySupport<S, R> imp
|
||||
Assert.notNull(sort, "Sort must not be null!");
|
||||
|
||||
return new FetchableFluentQueryByPredicate<>(predicate, entityType, resultType, sort.and(sort), properties, finder,
|
||||
pagedFinder, countOperation, existsOperation, context, projector);
|
||||
pagedFinder, countOperation, existsOperation, entityManager);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#as(java.lang.Class)
|
||||
*/
|
||||
@@ -110,10 +107,10 @@ class FetchableFluentQueryByPredicate<S, R> extends FluentQuerySupport<S, R> imp
|
||||
}
|
||||
|
||||
return new FetchableFluentQueryByPredicate<>(predicate, entityType, resultType, sort, properties, finder,
|
||||
pagedFinder, countOperation, existsOperation, context, projector);
|
||||
pagedFinder, countOperation, existsOperation, entityManager);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#project(java.util.Collection)
|
||||
*/
|
||||
@@ -121,10 +118,10 @@ class FetchableFluentQueryByPredicate<S, R> extends FluentQuerySupport<S, R> imp
|
||||
public FetchableFluentQuery<R> project(Collection<String> properties) {
|
||||
|
||||
return new FetchableFluentQueryByPredicate<>(predicate, entityType, resultType, sort, mergeProperties(properties),
|
||||
finder, pagedFinder, countOperation, existsOperation, context, projector);
|
||||
finder, pagedFinder, countOperation, existsOperation, entityManager);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#oneValue()
|
||||
*/
|
||||
@@ -142,7 +139,7 @@ class FetchableFluentQueryByPredicate<S, R> extends FluentQuerySupport<S, R> imp
|
||||
return results.isEmpty() ? null : getConversionFunction().apply(results.get(0));
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#firstValue()
|
||||
*/
|
||||
@@ -156,7 +153,7 @@ class FetchableFluentQueryByPredicate<S, R> extends FluentQuerySupport<S, R> imp
|
||||
return results.isEmpty() ? null : getConversionFunction().apply(results.get(0));
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#all()
|
||||
*/
|
||||
@@ -165,7 +162,7 @@ class FetchableFluentQueryByPredicate<S, R> extends FluentQuerySupport<S, R> imp
|
||||
return convert(createSortedAndProjectedQuery().fetch());
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#page(org.springframework.data.domain.Pageable)
|
||||
*/
|
||||
@@ -174,7 +171,7 @@ class FetchableFluentQueryByPredicate<S, R> extends FluentQuerySupport<S, R> imp
|
||||
return pageable.isUnpaged() ? new PageImpl<>(all()) : readPage(pageable);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#stream()
|
||||
*/
|
||||
@@ -186,7 +183,7 @@ class FetchableFluentQueryByPredicate<S, R> extends FluentQuerySupport<S, R> imp
|
||||
.map(getConversionFunction());
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#count()
|
||||
*/
|
||||
@@ -195,7 +192,7 @@ class FetchableFluentQueryByPredicate<S, R> extends FluentQuerySupport<S, R> imp
|
||||
return countOperation.apply(predicate);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery#exists()
|
||||
*/
|
||||
@@ -206,8 +203,12 @@ class FetchableFluentQueryByPredicate<S, R> extends FluentQuerySupport<S, R> imp
|
||||
|
||||
private AbstractJPAQuery<?, ?> createSortedAndProjectedQuery() {
|
||||
|
||||
final AbstractJPAQuery<?, ?> query = finder.apply(sort);
|
||||
projector.apply(entityType, query, properties);
|
||||
AbstractJPAQuery<?, ?> query = finder.apply(sort);
|
||||
|
||||
if (!properties.isEmpty()) {
|
||||
query.setHint(EntityGraphFactory.HINT, EntityGraphFactory.create(entityManager, entityType, properties));
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,9 +23,6 @@ import java.util.function.Function;
|
||||
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
@@ -41,15 +38,12 @@ abstract class FluentQuerySupport<S, R> {
|
||||
|
||||
protected final Class<R> resultType;
|
||||
protected final Sort sort;
|
||||
/** Properties on which the query projects. {@literal null} stands for no special projection. */
|
||||
protected final Set<String> properties;
|
||||
protected final MappingContext<? extends PersistentEntity<?, ?>, ? extends PersistentProperty<?>> context;
|
||||
protected final Class<S> entityType;
|
||||
|
||||
private final SpelAwareProxyProjectionFactory projectionFactory = new SpelAwareProxyProjectionFactory();
|
||||
|
||||
FluentQuerySupport(Class<R> resultType, Sort sort, @Nullable Collection<String> properties,
|
||||
MappingContext<? extends PersistentEntity<?, ?>, ? extends PersistentProperty<?>> context, Class<S> entityType) {
|
||||
FluentQuerySupport(Class<R> resultType, Sort sort, @Nullable Collection<String> properties, Class<S> entityType) {
|
||||
|
||||
this.resultType = resultType;
|
||||
this.sort = sort;
|
||||
@@ -57,10 +51,9 @@ abstract class FluentQuerySupport<S, R> {
|
||||
if (properties != null) {
|
||||
this.properties = new HashSet<>(properties);
|
||||
} else {
|
||||
this.properties = new HashSet<>();
|
||||
this.properties = Collections.emptySet();
|
||||
}
|
||||
|
||||
this.context = context;
|
||||
this.entityType = entityType;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.jpa.repository.support;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.EntityGraph;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.Subgraph;
|
||||
|
||||
import org.springframework.data.mapping.PropertyPath;
|
||||
|
||||
/**
|
||||
* Turns a collection of property paths to an {@link EntityGraph} and applies it to a query abstraction
|
||||
*
|
||||
* @param <Q> the type of the query abstraction.
|
||||
* @author Jens Schauder
|
||||
* @since 2.6
|
||||
*/
|
||||
abstract class Projector<Q> {
|
||||
|
||||
private final EntityManager entityManager;
|
||||
|
||||
protected Projector(EntityManager entityManager) {
|
||||
this.entityManager = entityManager;
|
||||
}
|
||||
|
||||
public void apply(Class<?> domainType, Q query, Set<String> properties) {
|
||||
|
||||
if (!properties.isEmpty()) {
|
||||
|
||||
final javax.persistence.EntityGraph<?> entityGraph = entityManager.createEntityGraph(domainType);
|
||||
|
||||
for (String property : properties) {
|
||||
|
||||
Subgraph<Object> subgraph = null;
|
||||
|
||||
for (PropertyPath path : PropertyPath.from(property, domainType)) {
|
||||
|
||||
if (path.hasNext()) {
|
||||
subgraph = subgraph == null ? entityGraph.addSubgraph(path.getSegment())
|
||||
: subgraph.addSubgraph(path.getSegment());
|
||||
} else {
|
||||
|
||||
if (subgraph == null) {
|
||||
entityGraph.addAttributeNodes(path.getSegment());
|
||||
} else {
|
||||
subgraph.addAttributeNodes(path.getSegment());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
applyEntityGraph(query, entityGraph);
|
||||
}
|
||||
}
|
||||
|
||||
abstract void applyEntityGraph(Q query, EntityGraph<?> entityGraph);
|
||||
}
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.springframework.data.jpa.repository.support;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiFunction;
|
||||
@@ -28,7 +27,6 @@ import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.jpa.mapping.JpaMetamodelMappingContext;
|
||||
import org.springframework.data.jpa.repository.EntityGraph;
|
||||
import org.springframework.data.querydsl.EntityPathResolver;
|
||||
import org.springframework.data.querydsl.QSort;
|
||||
@@ -69,7 +67,7 @@ public class QuerydslJpaPredicateExecutor<T> implements QuerydslPredicateExecuto
|
||||
/**
|
||||
* Creates a new {@link QuerydslJpaPredicateExecutor} from the given domain class and {@link EntityManager} and uses
|
||||
* the given {@link EntityPathResolver} to translate the domain class into an {@link EntityPath}.
|
||||
*
|
||||
*
|
||||
* @param entityInformation must not be {@literal null}.
|
||||
* @param entityManager must not be {@literal null}.
|
||||
* @param resolver must not be {@literal null}.
|
||||
@@ -167,7 +165,7 @@ public class QuerydslJpaPredicateExecutor<T> implements QuerydslPredicateExecuto
|
||||
return PageableExecutionUtils.getPage(query.fetch(), pageable, countQuery::fetchCount);
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.querydsl.QuerydslPredicateExecutor#findBy(com.querydsl.core.types.Predicate, java.util.function.Function)
|
||||
*/
|
||||
@@ -206,8 +204,7 @@ public class QuerydslJpaPredicateExecutor<T> implements QuerydslPredicateExecuto
|
||||
pagedFinder, //
|
||||
this::count, //
|
||||
this::exists, //
|
||||
new JpaMetamodelMappingContext(Collections.singleton(this.entityManager.getMetamodel())), //
|
||||
new QuerydslProjector(entityManager) //
|
||||
entityManager //
|
||||
);
|
||||
|
||||
return queryFunction.apply((FetchableFluentQuery<S>) fluentQuery);
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.jpa.repository.support;
|
||||
|
||||
import javax.persistence.EntityGraph;
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
import com.querydsl.jpa.impl.AbstractJPAQuery;
|
||||
|
||||
/**
|
||||
* Applies fetchgraph hints to {@code AbstractJPAQuery}.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @since 2.6
|
||||
*/
|
||||
class QuerydslProjector extends Projector<AbstractJPAQuery<?, ?>> {
|
||||
|
||||
QuerydslProjector(EntityManager entityManager) {
|
||||
super(entityManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
void applyEntityGraph(AbstractJPAQuery<?, ?> query, EntityGraph<?> entityGraph) {
|
||||
query.setHint("javax.persistence.fetchgraph", entityGraph);
|
||||
}
|
||||
}
|
||||
@@ -48,15 +48,11 @@ import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.jpa.convert.QueryByExamplePredicateBuilder;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.data.jpa.mapping.JpaMetamodelMappingContext;
|
||||
import org.springframework.data.jpa.provider.PersistenceProvider;
|
||||
import org.springframework.data.jpa.repository.EntityGraph;
|
||||
import org.springframework.data.jpa.repository.query.EscapeCharacter;
|
||||
import org.springframework.data.jpa.repository.query.QueryUtils;
|
||||
import org.springframework.data.jpa.repository.support.QueryHints.NoHints;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.PersistentProperty;
|
||||
import org.springframework.data.mapping.context.MappingContext;
|
||||
import org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery;
|
||||
import org.springframework.data.support.PageableExecutionUtils;
|
||||
import org.springframework.data.util.ProxyUtils;
|
||||
@@ -94,7 +90,6 @@ public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T
|
||||
private final JpaEntityInformation<T, ?> entityInformation;
|
||||
private final EntityManager em;
|
||||
private final PersistenceProvider provider;
|
||||
private final MappingContext<? extends PersistentEntity<?, ?>, ? extends PersistentProperty<?>> context;
|
||||
|
||||
private @Nullable CrudMethodMetadata metadata;
|
||||
private EscapeCharacter escapeCharacter = EscapeCharacter.DEFAULT;
|
||||
@@ -113,9 +108,6 @@ public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T
|
||||
this.entityInformation = entityInformation;
|
||||
this.em = entityManager;
|
||||
this.provider = PersistenceProvider.fromEntityManager(entityManager);
|
||||
this.context = em.getMetamodel() != null //
|
||||
? new JpaMetamodelMappingContext(Collections.singleton(em.getMetamodel())) //
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -595,7 +587,7 @@ public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T
|
||||
};
|
||||
|
||||
FetchableFluentQuery<S> fluentQuery = new FetchableFluentQueryByExample<>(example, finder, this::count,
|
||||
this::exists, this.context, this.em, this.escapeCharacter);
|
||||
this::exists, this.em, this.escapeCharacter);
|
||||
|
||||
return queryFunction.apply(fluentQuery);
|
||||
}
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright 2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.jpa.repository.support;
|
||||
|
||||
import javax.persistence.EntityGraph;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.TypedQuery;
|
||||
|
||||
/**
|
||||
* Applies fetchgraph hints to {@code TypedQuery}.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @since 2.6
|
||||
*/
|
||||
public class TypedQueryProjector extends Projector<TypedQuery<?>> {
|
||||
|
||||
public TypedQueryProjector(EntityManager entityManager) {
|
||||
super(entityManager);
|
||||
}
|
||||
|
||||
void applyEntityGraph(TypedQuery<?> query, EntityGraph<?> entityGraph) {
|
||||
query.setHint("javax.persistence.fetchgraph", entityGraph);
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,6 @@
|
||||
package org.springframework.data.jpa.repository.support;
|
||||
|
||||
import static java.util.Arrays.*;
|
||||
import static java.util.Collections.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.util.HashSet;
|
||||
@@ -28,18 +27,16 @@ import javax.persistence.Subgraph;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import com.querydsl.jpa.impl.AbstractJPAQuery;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link QuerydslProjector}.
|
||||
* Unit tests for {@link EntityGraphFactory}.
|
||||
*
|
||||
* @author Jens Schauder
|
||||
*/
|
||||
public class QuerydslProjectorUnitTests {
|
||||
@SuppressWarnings("rawtypes")
|
||||
class EntityGraphFactoryUnitTests {
|
||||
|
||||
EntityManager em = mock(EntityManager.class);
|
||||
private EntityGraph entityGraph;
|
||||
private AbstractJPAQuery jpaQuery = mock(AbstractJPAQuery.class);
|
||||
EntityGraph entityGraph;
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
@@ -48,21 +45,14 @@ public class QuerydslProjectorUnitTests {
|
||||
when(em.createEntityGraph(DummyEntity.class)).thenReturn(entityGraph);
|
||||
}
|
||||
|
||||
// GH-2329
|
||||
@Test
|
||||
void emptySetOfPropertiesDoesNotCreateEntityGraph() {
|
||||
new QuerydslProjector(em).apply(DummyEntity.class, jpaQuery, emptySet());
|
||||
}
|
||||
|
||||
// GH-2329
|
||||
@Test
|
||||
void simpleSetOfPropertiesGetRegistered() {
|
||||
|
||||
final HashSet<String> properties = new HashSet<>(asList("one", "two"));
|
||||
HashSet<String> properties = new HashSet<>(asList("one", "two"));
|
||||
|
||||
new QuerydslProjector(em).apply(DummyEntity.class, jpaQuery, properties);
|
||||
entityGraph = EntityGraphFactory.create(em, DummyEntity.class, properties);
|
||||
|
||||
verify(jpaQuery).setHint("javax.persistence.fetchgraph", entityGraph);
|
||||
verify(entityGraph).addAttributeNodes("one");
|
||||
verify(entityGraph).addAttributeNodes("two");
|
||||
}
|
||||
@@ -71,20 +61,18 @@ public class QuerydslProjectorUnitTests {
|
||||
@Test
|
||||
void setOfCompositePropertiesGetRegisteredPiecewise() {
|
||||
|
||||
final HashSet<String> properties = new HashSet<>(asList("one.two", "eins.zwei.drei"));
|
||||
HashSet<String> properties = new HashSet<>(asList("one.two", "eins.zwei.drei"));
|
||||
|
||||
new QuerydslProjector(em).apply(DummyEntity.class, jpaQuery, properties);
|
||||
|
||||
verify(jpaQuery).setHint("javax.persistence.fetchgraph", entityGraph);
|
||||
entityGraph = EntityGraphFactory.create(em, DummyEntity.class, properties);
|
||||
|
||||
verify(entityGraph).addSubgraph("one");
|
||||
Subgraph one = entityGraph.addSubgraph("one");
|
||||
Subgraph<?> one = entityGraph.addSubgraph("one");
|
||||
verify(one).addAttributeNodes("two");
|
||||
|
||||
verify(entityGraph).addSubgraph("eins");
|
||||
Subgraph eins = entityGraph.addSubgraph("eins");
|
||||
Subgraph<?> eins = entityGraph.addSubgraph("eins");
|
||||
verify(eins).addSubgraph("zwei");
|
||||
Subgraph zwei = eins.addSubgraph("zwei");
|
||||
Subgraph<?> zwei = eins.addSubgraph("zwei");
|
||||
verify(zwei).addAttributeNodes("drei");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user