DATAJPA-1535 - Fix SpringJpaRepository.delete(…) for repositories working with mapped superclasses.

The new optimized implementation of SimpleJpaRepository.delete(…) used the Java type registered with the EntityInformation backing the repository, not the concrete type of the entity handed into the method. For mapped superclasses that's problematic as the JPA provider does not know which concrete type to actually look for. We now simply use the type of the actual instance to perform the by id lookup.
This commit is contained in:
Oliver Drotbohm
2019-07-16 21:09:03 +02:00
parent 864f44493b
commit 3a24c6d0d4
3 changed files with 30 additions and 3 deletions

View File

@@ -179,8 +179,9 @@ public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T
* (non-Javadoc)
* @see org.springframework.data.repository.CrudRepository#delete(java.lang.Object)
*/
@Transactional
@Override
@Transactional
@SuppressWarnings("unchecked")
public void delete(T entity) {
Assert.notNull(entity, "Entity must not be null!");
@@ -189,11 +190,13 @@ public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T
return;
}
T existing = em.find(entityInformation.getJavaType(), entityInformation.getId(entity));
T existing = (T) em.find(entity.getClass(), entityInformation.getId(entity));
// if the entity to be deleted doesn't exist, delete is a NOOP
if (existing == null) {
return;
}
em.remove(em.contains(entity) ? entity : em.merge(entity));
}

View File

@@ -15,6 +15,8 @@
*/
package org.springframework.data.jpa.domain.sample;
import lombok.Getter;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
@@ -27,7 +29,7 @@ import javax.persistence.Version;
@MappedSuperclass
public abstract class AbstractMappedType {
@Id @GeneratedValue Long id;
@Id @GeneratedValue @Getter Long id;
@Version Long version;
String attribute1;

View File

@@ -19,18 +19,23 @@ import static org.assertj.core.api.Assertions.*;
import java.util.List;
import javax.persistence.EntityManager;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.sample.AbstractMappedType;
import org.springframework.data.jpa.domain.sample.ConcreteType1;
import org.springframework.data.jpa.domain.sample.ConcreteType2;
import org.springframework.data.jpa.repository.sample.ConcreteRepository1;
import org.springframework.data.jpa.repository.sample.ConcreteRepository2;
import org.springframework.data.jpa.repository.sample.MappedTypeRepository;
import org.springframework.data.jpa.repository.sample.SampleConfig;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
import org.springframework.data.repository.CrudRepository;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
@@ -49,6 +54,8 @@ public class MappedTypeRepositoryIntegrationTests {
@Autowired ConcreteRepository1 concreteRepository1;
@Autowired ConcreteRepository2 concreteRepository2;
@Autowired EntityManager entityManager;
@Test // DATAJPA-170
public void supportForExpressionBasedQueryMethods() {
@@ -73,4 +80,19 @@ public class MappedTypeRepositoryIntegrationTests {
assertThat(page.getNumberOfElements()).isEqualTo(1);
}
@Test // DATAJPA-1535
@SuppressWarnings("unchecked")
public void deletesConcreteInstancesForRepositoryBoundToMappedSuperclass() {
JpaRepositoryFactory factory = new JpaRepositoryFactory(entityManager);
CustomMappedTypeRepository<AbstractMappedType> repository = factory.getRepository(CustomMappedTypeRepository.class);
ConcreteType1 entity = repository.save(new ConcreteType1());
assertThatCode(() -> repository.delete(entity)).doesNotThrowAnyException();
assertThat(concreteRepository1.findById(entity.getId())).isEmpty();
}
private interface CustomMappedTypeRepository<T extends AbstractMappedType> extends CrudRepository<T, Long> {}
}