Use IN predicate for deleteAllInBatch(…).
We now use an IN (?1) predicate to avoid repeated OR alias = … variants to ease on JPQL parsing. With a sufficient number of predicates, parsers dive into a very deep parsing tree risking a StackOverflowError. Closes #2870
This commit is contained in:
@@ -15,10 +15,10 @@
|
||||
*/
|
||||
package org.springframework.data.jpa.repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.persistence.EntityManager;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.domain.Example;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.repository.ListCrudRepository;
|
||||
@@ -38,7 +38,8 @@ import org.springframework.data.repository.query.QueryByExampleExecutor;
|
||||
* @author Jens Schauder
|
||||
*/
|
||||
@NoRepositoryBean
|
||||
public interface JpaRepository<T, ID> extends ListCrudRepository<T, ID>, ListPagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
|
||||
public interface JpaRepository<T, ID>
|
||||
extends ListCrudRepository<T, ID>, ListPagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
|
||||
|
||||
/**
|
||||
* Flushes all pending changes to the database.
|
||||
@@ -66,6 +67,8 @@ public interface JpaRepository<T, ID> extends ListCrudRepository<T, ID>, ListPag
|
||||
* Deletes the given entities in a batch which means it will create a single query. This kind of operation leaves JPAs
|
||||
* first level cache and the database out of sync. Consider flushing the {@link EntityManager} before calling this
|
||||
* method.
|
||||
* <p>
|
||||
* It will also NOT honor cascade semantics of JPA, nor will it emit JPA lifecycle events.
|
||||
*
|
||||
* @param entities entities to be deleted. Must not be {@literal null}.
|
||||
* @deprecated Use {@link #deleteAllInBatch(Iterable)} instead.
|
||||
@@ -80,8 +83,8 @@ public interface JpaRepository<T, ID> extends ListCrudRepository<T, ID>, ListPag
|
||||
* first level cache and the database out of sync. Consider flushing the {@link EntityManager} before calling this
|
||||
* method.
|
||||
* <p>
|
||||
* It will also NOT honor cascade semantics of JPA, nor will it emit JPA lifecycle events.
|
||||
*</p>
|
||||
* It will also NOT honor cascade semantics of JPA, nor will it emit JPA lifecycle events.
|
||||
*
|
||||
* @param entities entities to be deleted. Must not be {@literal null}.
|
||||
* @since 2.5
|
||||
*/
|
||||
|
||||
@@ -40,16 +40,7 @@ import jakarta.persistence.metamodel.SingularAttribute;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Member;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -292,9 +283,8 @@ public abstract class QueryUtils {
|
||||
Set<String> selectionAliases = getFunctionAliases(query);
|
||||
selectionAliases.addAll(getFieldAliases(query));
|
||||
|
||||
String orderClauses = sort.stream()
|
||||
.map(order -> getOrderClause(joinAliases, selectionAliases, alias, order))
|
||||
.collect(Collectors.joining(", "));
|
||||
String orderClauses = sort.stream().map(order -> getOrderClause(joinAliases, selectionAliases, alias, order))
|
||||
.collect(Collectors.joining(", "));
|
||||
|
||||
builder.append(orderClauses);
|
||||
|
||||
@@ -532,7 +522,6 @@ public abstract class QueryUtils {
|
||||
* @param entityManager must not be {@literal null}.
|
||||
* @return Guaranteed to be not {@literal null}.
|
||||
*/
|
||||
|
||||
public static <T> Query applyAndBind(String queryString, Iterable<T> entities, EntityManager entityManager) {
|
||||
|
||||
Assert.notNull(queryString, "Querystring must not be null");
|
||||
@@ -546,30 +535,8 @@ public abstract class QueryUtils {
|
||||
}
|
||||
|
||||
String alias = detectAlias(queryString);
|
||||
StringBuilder builder = new StringBuilder(queryString);
|
||||
builder.append(" where");
|
||||
|
||||
int i = 0;
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
|
||||
iterator.next();
|
||||
|
||||
builder.append(String.format(" %s = ?%d", alias, ++i));
|
||||
|
||||
if (iterator.hasNext()) {
|
||||
builder.append(" or");
|
||||
}
|
||||
}
|
||||
|
||||
Query query = entityManager.createQuery(builder.toString());
|
||||
|
||||
iterator = entities.iterator();
|
||||
i = 0;
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
query.setParameter(++i, iterator.next());
|
||||
}
|
||||
Query query = entityManager.createQuery("%s where %s IN (?1)".formatted(queryString, alias));
|
||||
query.setParameter(1, entities instanceof Collection<T> ? entities : Streamable.of(entities).toList());
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user