Added exists method with specification to JpaSpecificationExecutor.
It is now possible to make existence checks based on a `Specification`. This is an addition to checking existence with using an `Example`. Closes #2388 Original pull request #2449
This commit is contained in:
committed by
Jens Schauder
parent
8fb25c6b45
commit
36c9b4d660
@@ -29,6 +29,7 @@ import org.springframework.lang.Nullable;
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @author Diego Krupitza
|
||||
*/
|
||||
public interface JpaSpecificationExecutor<T> {
|
||||
|
||||
@@ -74,4 +75,13 @@ public interface JpaSpecificationExecutor<T> {
|
||||
* @return the number of instances.
|
||||
*/
|
||||
long count(@Nullable Specification<T> spec);
|
||||
|
||||
/**
|
||||
* Checks whether the data store contains elements that match the given {@link Specification}.
|
||||
*
|
||||
* @param spec the {@link Specification} to use for the existence check. Must not be {@literal null}.
|
||||
* @return <code>true</code> if the data store contains elements that match the given {@link Specification} otherwise
|
||||
* <code>false</code>.
|
||||
*/
|
||||
boolean exists(Specification<T> spec);
|
||||
}
|
||||
|
||||
@@ -15,12 +15,16 @@
|
||||
*/
|
||||
package org.springframework.data.jpa.repository.support;
|
||||
|
||||
import static org.springframework.data.jpa.repository.query.QueryUtils.*;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.persistence.*;
|
||||
import javax.persistence.criteria.*;
|
||||
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.data.domain.Example;
|
||||
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.domain.*;
|
||||
import org.springframework.data.jpa.convert.QueryByExamplePredicateBuilder;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.data.jpa.provider.PersistenceProvider;
|
||||
@@ -37,29 +41,6 @@ import org.springframework.stereotype.Repository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.LockModeType;
|
||||
import javax.persistence.NoResultException;
|
||||
import javax.persistence.Parameter;
|
||||
import javax.persistence.Query;
|
||||
import javax.persistence.TypedQuery;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.ParameterExpression;
|
||||
import javax.persistence.criteria.Path;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static org.springframework.data.jpa.repository.query.QueryUtils.*;
|
||||
|
||||
/**
|
||||
* Default implementation of the {@link org.springframework.data.repository.CrudRepository} interface. This will offer
|
||||
* you a more sophisticated interface than the plain {@link EntityManager} .
|
||||
@@ -80,6 +61,7 @@ import static org.springframework.data.jpa.repository.query.QueryUtils.*;
|
||||
* @author Greg Turnquist
|
||||
* @author Yanming Zhou
|
||||
* @author Ernst-Jan van der Laan
|
||||
* @author Diego Krupitza
|
||||
*/
|
||||
@Repository
|
||||
@Transactional(readOnly = true)
|
||||
@@ -555,6 +537,20 @@ public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T
|
||||
return query.setMaxResults(1).getResultList().size() == 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jpa.repository.JpaSpecificationExecutor#exists(org.springframework.data.jpa.domain.Specification)
|
||||
*/
|
||||
@Override
|
||||
public boolean exists(Specification<T> spec) {
|
||||
|
||||
CriteriaQuery<Integer> cq = this.em.getCriteriaBuilder().createQuery(Integer.class);
|
||||
cq.select(this.em.getCriteriaBuilder().literal(1));
|
||||
applySpecificationToCriteria(spec, getDomainClass(), cq);
|
||||
TypedQuery<Integer> query = applyRepositoryMethodMetadata(this.em.createQuery(cq));
|
||||
return query.setMaxResults(1).getResultList().size() == 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.QueryByExampleExecutor#findAll(org.springframework.data.domain.Example)
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.springframework.data.jpa.domain.Specification;
|
||||
* Collection of {@link Specification}s for a {@link User}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Diego Krupitza
|
||||
*/
|
||||
public class UserSpecifications {
|
||||
|
||||
@@ -69,6 +70,17 @@ public class UserSpecifications {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link Specification} to do an age check.
|
||||
*
|
||||
* @param age upper (exclusive) bound of the age
|
||||
* @return
|
||||
*/
|
||||
public static Specification<User> userHasAgeLess(final Integer age) {
|
||||
|
||||
return (root, query, cb) -> cb.lessThan(root.get("age").as(Integer.class), age);
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link Specification} to do a like-match on a {@link User}'s lastname but also adding a sort order on the
|
||||
* firstname.
|
||||
|
||||
@@ -96,6 +96,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
* @author Sander Krabbenborg
|
||||
* @author Jesse Wouters
|
||||
* @author Greg Turnquist
|
||||
* @author Diego Krupitza
|
||||
*/
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@ContextConfiguration("classpath:application-context.xml")
|
||||
@@ -2640,6 +2641,17 @@ public class UserRepositoryTests {
|
||||
assertThat(repository.findAllInterfaceProjectedBy()).hasSize(4);
|
||||
}
|
||||
|
||||
@Test // GH-2388
|
||||
void existsWithSpec() {
|
||||
flushTestUsers();
|
||||
|
||||
Specification<User> minorSpec = userHasAgeLess(18);
|
||||
Specification<User> hundredYearsOld = userHasAgeLess(100);
|
||||
|
||||
assertThat(repository.exists(minorSpec)).isFalse();
|
||||
assertThat(repository.exists(hundredYearsOld)).isTrue();
|
||||
}
|
||||
|
||||
private Page<User> executeSpecWithSort(Sort sort) {
|
||||
|
||||
flushTestUsers();
|
||||
|
||||
Reference in New Issue
Block a user