From 6b1aabfa912dc6b0afb9b403802401f86c42fa97 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Thu, 3 Feb 2011 19:57:22 +0000 Subject: [PATCH] Added deleteInBatch method to JpaRepository. Reverted implementation of delete(Iterable entities) to iterate over the entities as creating a query can cause the persistence provider to choke on really large entity sets. Beyond that triggering a query would require us to clear the persistence context which might not be wanted in every case. Thus an additional method deleteInBatch(Iterable entities) especially available on the JpaRepository interface now triggers the query but clearly states the assumptions and side effects in the JavaDoc. Removed some obsolete finals and an obsolete method. --- .../data/jpa/repository/JpaRepository.java | 12 +++ .../support/SimpleJpaRepository.java | 87 ++++++++++--------- .../jpa/repository/UserRepositoryTests.java | 12 +++ 3 files changed, 72 insertions(+), 39 deletions(-) diff --git a/src/main/java/org/springframework/data/jpa/repository/JpaRepository.java b/src/main/java/org/springframework/data/jpa/repository/JpaRepository.java index cc4726151..8bfd19b4f 100644 --- a/src/main/java/org/springframework/data/jpa/repository/JpaRepository.java +++ b/src/main/java/org/springframework/data/jpa/repository/JpaRepository.java @@ -18,6 +18,8 @@ package org.springframework.data.jpa.repository; import java.io.Serializable; import java.util.List; +import javax.persistence.EntityManager; + import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.domain.Specification; @@ -75,4 +77,14 @@ public interface JpaRepository extends * @return the saved entity */ T saveAndFlush(T entity); + + + /** + * Deletes the given entities in a batch which means it will create a single + * {@link Query}. Assume that we will clear the {@link EntityManager} after + * the call. + * + * @param entities + */ + void deleteInBatch(Iterable entities); } diff --git a/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java b/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java index a3a83774f..50f633658 100644 --- a/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java +++ b/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java @@ -34,7 +34,6 @@ import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.data.jpa.domain.Specification; -import org.springframework.data.jpa.repository.query.QueryUtils; import org.springframework.data.repository.Repository; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.Assert; @@ -58,6 +57,13 @@ public class SimpleJpaRepository extends private final PersistenceProvider provider; + /** + * Creates a new {@link SimpleJpaRepository} to manage objects of the given + * domain type. + * + * @param domainClass + * @param entityManager + */ public SimpleJpaRepository(Class domainClass, EntityManager entityManager) { super(domainClass); @@ -87,16 +93,16 @@ public class SimpleJpaRepository extends /** * Factory method to create {@link SimpleJpaRepository} instances. * - * @param the type of the entity to handle - * @param the type of the entity's identifier - * @param entityManager the {@link EntityManager} backing the repository * @param domainClass the domain class to handle + * @param entityManager the {@link EntityManager} backing the repository + * @param the type of the entity to handle + * @param the type of the entity's identifier * @return */ - public static Repository create( - final EntityManager entityManager, final Class domainClass) { + public static Repository create( + Class domainClass, EntityManager entityManager) { - return new SimpleJpaRepository(domainClass, entityManager); + return new SimpleJpaRepository(domainClass, entityManager); } @@ -106,7 +112,7 @@ public class SimpleJpaRepository extends * @see * org.springframework.data.repository.Repository#delete(java.lang.Object) */ - public void delete(final T entity) { + public void delete(T entity) { em.remove(em.contains(entity) ? entity : em.merge(entity)); } @@ -118,7 +124,26 @@ public class SimpleJpaRepository extends * @see * org.springframework.data.repository.Repository#delete(java.lang.Iterable) */ - public void delete(final Iterable entities) { + public void delete(Iterable entities) { + + if (entities == null) { + return; + } + + for (T entity : entities) { + delete(entity); + } + } + + + /* + * (non-Javadoc) + * + * @see + * org.springframework.data.jpa.repository.JpaRepository#deleteInBatch(java + * .lang.Iterable) + */ + public void deleteInBatch(Iterable entities) { if (null == entities || !entities.iterator().hasNext()) { return; @@ -126,6 +151,7 @@ public class SimpleJpaRepository extends applyAndBind(getQueryString(DELETE_ALL_QUERY_STRING, getDomainClass()), entities, em).executeUpdate(); + em.clear(); } @@ -137,6 +163,7 @@ public class SimpleJpaRepository extends public void deleteAll() { em.createQuery(getDeleteAllQueryString()).executeUpdate(); + em.clear(); } @@ -148,11 +175,10 @@ public class SimpleJpaRepository extends * ) */ @Transactional(readOnly = true) - public T findById(final ID primaryKey) { + public T findById(ID id) { - Assert.notNull(primaryKey, "The given primaryKey must not be null!"); - - return em.find(getDomainClass(), primaryKey); + Assert.notNull(id, "The given id must not be null!"); + return em.find(getDomainClass(), id); } @@ -164,11 +190,10 @@ public class SimpleJpaRepository extends * ) */ @Transactional(readOnly = true) - public boolean exists(final ID primaryKey) { + public boolean exists(ID id) { - Assert.notNull(primaryKey, "The given primary key must not be null!"); - - return null != findById(primaryKey); + Assert.notNull(id, "The given id must not be null!"); + return null != findById(id); } @@ -192,7 +217,7 @@ public class SimpleJpaRepository extends * .data.domain.Sort) */ @Transactional(readOnly = true) - public List findAll(final Sort sort) { + public List findAll(Sort sort) { return getQuery(null, sort).getResultList(); } @@ -205,7 +230,7 @@ public class SimpleJpaRepository extends * springframework.data.domain.Pageable) */ @Transactional(readOnly = true) - public Page findAll(final Pageable pageable) { + public Page findAll(Pageable pageable) { if (null == pageable) { return new PageImpl(findAll()); @@ -280,7 +305,7 @@ public class SimpleJpaRepository extends * @see * org.springframework.data.repository.Repository#save(java.lang.Object) */ - public T save(final T entity) { + public T save(T entity) { if (getIsNewStrategy().isNew(entity)) { em.persist(entity); @@ -298,7 +323,7 @@ public class SimpleJpaRepository extends * org.springframework.data.jpa.repository.JpaRepository#saveAndFlush(java * .lang.Object) */ - public T saveAndFlush(final T entity) { + public T saveAndFlush(T entity) { T result = save(entity); flush(); @@ -340,30 +365,14 @@ public class SimpleJpaRepository extends } - /** - * Reads a page of entities for the given JPQL query. - * - * @param pageable - * @param query - * @return a page of entities for the given JPQL query - */ - protected Page readPage(final Pageable pageable, final String query) { - - String queryString = QueryUtils.applySorting(query, pageable.getSort()); - TypedQuery jpaQuery = em.createQuery(queryString, getDomainClass()); - - return readPage(jpaQuery, pageable, null); - } - - /** * @param query * @param spec * @param pageable * @return */ - private Page readPage(final TypedQuery query, - final Pageable pageable, final Specification spec) { + private Page readPage(TypedQuery query, Pageable pageable, + Specification spec) { query.setFirstResult(pageable.getOffset()); query.setMaxResults(pageable.getPageSize()); diff --git a/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java b/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java index fa2f9bd51..915d0e28f 100644 --- a/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java @@ -225,6 +225,18 @@ public class UserRepositoryTests { } + @Test + public void batchDeleteColletionOfEntities() { + + flushTestUsers(); + + long before = repository.count(); + + repository.deleteInBatch(Arrays.asList(firstUser, secondUser)); + assertThat(repository.count(), is(before - 2)); + } + + @Test public void deleteEmptyCollectionDoesNotDeleteAnything() {