Remove duplicated code.

See: #2327
Original Pull Request: #3654
This commit is contained in:
Mark Paluch
2024-09-25 09:44:40 +02:00
committed by Christoph Strobl
parent e1b76122ae
commit 826147e7cb
5 changed files with 41 additions and 17 deletions

View File

@@ -21,8 +21,6 @@ import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Set;
import org.springframework.data.domain.KeysetScrollPosition;
import org.springframework.data.domain.Sort;
@@ -77,9 +75,7 @@ class JpaKeysetScrollQueryCreator extends JpaQueryCreator {
Sort sortToUse = KeysetScrollSpecification.createSort(scrollPosition, sort, entityInformation);
Set<String> selection = new LinkedHashSet<>(returnedType.getInputProperties());
sortToUse.forEach(it -> selection.add(it.getProperty()));
return selection;
return KeysetScrollDelegate.getProjectionInputProperties(entityInformation, returnedType.getInputProperties(),
sortToUse);
}
}

View File

@@ -16,7 +16,9 @@
package org.springframework.data.jpa.repository.query;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
@@ -24,6 +26,7 @@ import org.springframework.data.domain.KeysetScrollPosition;
import org.springframework.data.domain.ScrollPosition.Direction;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Order;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.lang.Nullable;
/**
@@ -47,6 +50,25 @@ public class KeysetScrollDelegate {
return direction == Direction.FORWARD ? FORWARD : REVERSE;
}
/**
* Return a collection of property names required to construct a keyset selection query that include all keyset and
* identifier properties required to resume keyset scrolling.
*
* @param entity the underlying entity.
* @param projectionProperties projection property names.
* @param sort sort properties.
* @return a collection of property names required to construct a keyset selection query
*/
public static Collection<String> getProjectionInputProperties(JpaEntityInformation<?, ?> entity,
Collection<String> projectionProperties, Sort sort) {
Collection<String> properties = new LinkedHashSet<>(projectionProperties);
sort.forEach(it -> properties.add(it.getProperty()));
properties.addAll(entity.getIdAttributeNames());
return properties;
}
@Nullable
public <E, P> P createPredicate(KeysetScrollPosition keyset, Sort sort, QueryStrategy<E, P> strategy) {

View File

@@ -20,7 +20,6 @@ import jakarta.persistence.EntityManager;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Function;
@@ -34,6 +33,7 @@ import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.ScrollPosition;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Window;
import org.springframework.data.jpa.repository.query.KeysetScrollDelegate;
import org.springframework.data.jpa.repository.query.ScrollDelegate;
import org.springframework.data.projection.ProjectionFactory;
import org.springframework.data.repository.query.FluentQuery.FetchableFluentQuery;
@@ -219,13 +219,11 @@ class FetchableFluentQueryByPredicate<S, R> extends FluentQuerySupport<S, R> imp
List<String> inputProperties = returnedType.getInputProperties();
if (returnedType.needsCustomConstruction() && !inputProperties.isEmpty()) {
if (returnedType.needsCustomConstruction()) {
Collection<String> requiredSelection;
if (scrollPosition instanceof KeysetScrollPosition && returnedType.getReturnedType().isInterface()) {
requiredSelection = new LinkedHashSet<>(inputProperties);
sort.forEach(it -> requiredSelection.add(it.getProperty()));
entityInformation.getIdAttributeNames().forEach(requiredSelection::add);
requiredSelection = KeysetScrollDelegate.getProjectionInputProperties(entityInformation, inputProperties, sort);
} else {
requiredSelection = inputProperties;
}

View File

@@ -37,7 +37,6 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -58,6 +57,7 @@ import org.springframework.data.jpa.domain.Specification;
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.KeysetScrollDelegate;
import org.springframework.data.jpa.repository.query.KeysetScrollSpecification;
import org.springframework.data.jpa.repository.query.QueryUtils;
import org.springframework.data.jpa.repository.support.FetchableFluentQueryBySpecification.SpecificationScrollDelegate;
@@ -776,7 +776,7 @@ public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T
List<String> inputProperties = returnedType.getInputProperties();
if (returnedType.needsCustomConstruction() && !inputProperties.isEmpty()) {
if (returnedType.needsCustomConstruction()) {
query = (CriteriaQuery) (returnedType.getReturnedType().isInterface() ? builder.createTupleQuery()
: builder.createQuery(returnedType.getReturnedType()));
} else {
@@ -785,14 +785,12 @@ public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T
Root<S> root = applySpecificationToCriteria(spec, domainClass, query);
if (returnedType.needsCustomConstruction() && !inputProperties.isEmpty()) {
if (returnedType.needsCustomConstruction()) {
Collection<String> requiredSelection;
if (scrollPosition instanceof KeysetScrollPosition && returnedType.getReturnedType().isInterface()) {
requiredSelection = new LinkedHashSet<>(inputProperties);
sort.stream().map(Sort.Order::getProperty).forEach(requiredSelection::add);
entityInformation.getIdAttributeNames().forEach(requiredSelection::add);
requiredSelection = KeysetScrollDelegate.getProjectionInputProperties(entityInformation, inputProperties, sort);
} else {
requiredSelection = inputProperties;
}

View File

@@ -2960,6 +2960,16 @@ class UserRepositoryTests {
assertThat(users).hasSize(1);
}
@Test // GH-2327
void dynamicOpenProjectionReturningList() {
flushTestUsers();
List<UserProjectionUsingSpEL> users = repository.findAsListByFirstnameLike("%O%", UserProjectionUsingSpEL.class);
assertThat(users).hasSize(1);
}
@Test // DATAJPA-1179
void duplicateSpelsWorkAsIntended() {