Introduce delete(Specification) on JpaSpecificationExecutor.
Ever since JPA 2.1, CriteriaBuilder has offered createCriteriaDelete, returning a CriteriaDelete. With Spring Data JPA 3.0 rebased on JPA 3.0, we are able to guarantee this SPI, and hence rollout support for this feature. See #1262.
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
package org.springframework.data.jpa.domain;
|
||||
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaDelete;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import jakarta.persistence.criteria.Predicate;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
|
||||
@@ -87,6 +87,14 @@ public interface JpaSpecificationExecutor<T> {
|
||||
*/
|
||||
boolean exists(Specification<T> spec);
|
||||
|
||||
/**
|
||||
* Deletes by the {@link Specification} and returns the number of rows deleted.
|
||||
*
|
||||
* @param spec the {@link Specification} to use for the existence check. Must not be {@literal null}.
|
||||
* @return the number of entities deleted
|
||||
*/
|
||||
long delete(Specification<T> spec);
|
||||
|
||||
/**
|
||||
* Returns entities matching the given {@link Specification} applying the {@code queryFunction} that defines the query
|
||||
* and its result type.
|
||||
|
||||
@@ -24,6 +24,7 @@ import jakarta.persistence.Parameter;
|
||||
import jakarta.persistence.Query;
|
||||
import jakarta.persistence.TypedQuery;
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaDelete;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
import jakarta.persistence.criteria.ParameterExpression;
|
||||
import jakarta.persistence.criteria.Path;
|
||||
@@ -485,6 +486,21 @@ public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T
|
||||
return query.setMaxResults(1).getResultList().size() == 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long delete(Specification<T> spec) {
|
||||
|
||||
CriteriaBuilder builder = this.em.getCriteriaBuilder();
|
||||
CriteriaDelete<T> delete = builder.createCriteriaDelete(getDomainClass());
|
||||
|
||||
Predicate predicate = spec.toPredicate(delete.from(getDomainClass()), null, builder);
|
||||
|
||||
if (predicate != null) {
|
||||
delete.where(predicate);
|
||||
}
|
||||
|
||||
return this.em.createQuery(delete).executeUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S extends T> List<S> findAll(Example<S> example) {
|
||||
return getQuery(new ExampleSpecification<>(example, escapeCharacter), example.getProbeType(), Sort.unsorted())
|
||||
|
||||
@@ -2838,6 +2838,19 @@ public class UserRepositoryTests {
|
||||
assertThat(repository.exists(hundredYearsOld)).isTrue();
|
||||
}
|
||||
|
||||
@Test // GH-1262
|
||||
void deleteWithSpec() {
|
||||
|
||||
flushTestUsers();
|
||||
|
||||
Specification<User> usersWithEInTheirName = userHasFirstnameLike("e");
|
||||
|
||||
long initialCount = repository.count();
|
||||
assertThat(repository.delete(usersWithEInTheirName)).isEqualTo(3L);
|
||||
long finalCount = repository.count();
|
||||
assertThat(initialCount - finalCount).isEqualTo(3L);
|
||||
}
|
||||
|
||||
private Page<User> executeSpecWithSort(Sort sort) {
|
||||
|
||||
flushTestUsers();
|
||||
|
||||
@@ -943,6 +943,21 @@ List<Customer> customers = customerRepository.findAll(
|
||||
`Specification` offers some "`glue-code`" default methods to chain and combine `Specification` instances. These methods let you extend your data access layer by creating new `Specification` implementations and combining them with already existing implementations.
|
||||
====
|
||||
|
||||
And with JPA 2.1, the `CriteriaBuilder` API introduced `CriteriaDelete`. This is provided through `JpaSpecificationExecutor`'s `delete(Specification)` API.
|
||||
|
||||
.Using a `Specification` to delete entries.
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
Specification<User> ageLessThan18 = (root, query, cb) -> cb.lessThan(root.get("age").as(Integer.class), 18)
|
||||
|
||||
userRepository.delete(ageLessThan18);
|
||||
----
|
||||
The `Specification` builds up a criteria where the `age` field (cast as an integer) is less than `18`.
|
||||
Passed on to the `userRepository`, it will use JPA's `CriteriaDelete` feature to generate the right `DELETE` operation.
|
||||
It then returns the number of entities deleted.
|
||||
====
|
||||
|
||||
include::{spring-data-commons-docs}/query-by-example.adoc[leveloffset=+1]
|
||||
include::query-by-example.adoc[leveloffset=+1]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user