Polishing.

Rename Projector to EntityGraphFactory. Remove QuerydslProjector and TypedQueryProjector. Remove MappingContext creation.

See #2329
Original pull request: #2345.
This commit is contained in:
Mark Paluch
2021-10-29 12:01:17 +02:00
committed by Greg L. Turnquist
parent 83ba970465
commit d637ce35df
10 changed files with 134 additions and 249 deletions

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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");
}