DATAJPA-527 - Improved handling of CrudRepository.exists(ID) entities with complex composite id.

We now delegate the exists(…) check to findOne(…) in SimpleJpaRepository for entities that have a complex composite id via @IdClass. Previously we tried to generate a string based count query in that case, which didn't work since the parameter types for the IdClass attributes didn't match the values returned by entityInformation.getCompositeIdAttributeValue(…).

Polished JavaDoc in JpaEntityInformation.

Original pull request: #95.
This commit is contained in:
Thomas Darimont
2014-06-02 13:38:30 +02:00
committed by Oliver Gierke
parent 46bde70d81
commit 8d320c966d
4 changed files with 102 additions and 25 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2013 the original author or authors.
* Copyright 2011-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,7 +22,7 @@ import javax.persistence.metamodel.SingularAttribute;
import org.springframework.data.repository.core.EntityInformation;
/**
* Extension of {@link EntityInformation} to capture aditional JPA specific information about entities.
* Extension of {@link EntityInformation} to capture additional JPA specific information about entities.
*
* @author Oliver Gierke
* @author Thomas Darimont
@@ -38,7 +38,7 @@ public interface JpaEntityInformation<T, ID extends Serializable> extends Entity
SingularAttribute<? super T, ?> getIdAttribute();
/**
* Returns {@literal true} if the entity has a composite id
* Returns {@literal true} if the entity has a composite id.
*
* @return
*/

View File

@@ -233,27 +233,39 @@ public class SimpleJpaRepository<T, ID extends Serializable> implements JpaRepos
Assert.notNull(id, "The given id must not be null!");
if (entityInformation.getIdAttribute() != null) {
String placeholder = provider.getCountQueryPlaceholder();
String entityName = entityInformation.getEntityName();
Iterable<String> idAttributeNames = entityInformation.getIdAttributeNames();
String existsQuery = QueryUtils.getExistsQueryString(entityName, placeholder, idAttributeNames);
TypedQuery<Long> query = em.createQuery(existsQuery, Long.class);
if (entityInformation.hasCompositeId()) {
for (String idAttributeName : idAttributeNames) {
query.setParameter(idAttributeName, entityInformation.getCompositeIdAttributeValue(id, idAttributeName));
}
} else {
query.setParameter(idAttributeNames.iterator().next(), id);
}
return query.getSingleResult() == 1L;
} else {
if (entityInformation.getIdAttribute() == null) {
return findOne(id) != null;
}
String placeholder = provider.getCountQueryPlaceholder();
String entityName = entityInformation.getEntityName();
Iterable<String> idAttributeNames = entityInformation.getIdAttributeNames();
String existsQuery = QueryUtils.getExistsQueryString(entityName, placeholder, idAttributeNames);
TypedQuery<Long> query = em.createQuery(existsQuery, Long.class);
if (!entityInformation.hasCompositeId()) {
query.setParameter(idAttributeNames.iterator().next(), id);
return query.getSingleResult() == 1L;
}
for (String idAttributeName : idAttributeNames) {
Object idAttributeValue = entityInformation.getCompositeIdAttributeValue(id, idAttributeName);
boolean complexIdParameterValueDiscovered = idAttributeValue != null
&& !query.getParameter(idAttributeName).getParameterType().isAssignableFrom(idAttributeValue.getClass());
if (complexIdParameterValueDiscovered) {
// fall-back to findOne(id) which does the proper mapping for the parameter.
return findOne(id) != null;
}
query.setParameter(idAttributeName, idAttributeValue);
}
return query.getSingleResult() == 1L;
}
/*

View File

@@ -215,4 +215,52 @@ public class RepositoryWithCompositeKeyTests {
assertThat(result.get(0), is(emp3));
assertThat(result.get(1), is(emp1));
}
/**
* @see DATAJPA-527
*/
@Test
public void testExistsWithIdClass() {
IdClassExampleDepartment dep = new IdClassExampleDepartment();
dep.setName("TestDepartment");
dep.setDepartmentId(-1);
IdClassExampleEmployee emp = new IdClassExampleEmployee();
emp.setDepartment(dep);
employeeRepositoryWithIdClass.save(emp);
IdClassExampleEmployeePK key = new IdClassExampleEmployeePK();
key.setDepartment(dep.getDepartmentId());
key.setEmpId(emp.getEmpId());
assertThat(employeeRepositoryWithIdClass.exists(key), is(true));
}
/**
* @see DATAJPA-527
*/
@Test
public void testExistsWithEmbeddedId() {
EmbeddedIdExampleDepartment dep1 = new EmbeddedIdExampleDepartment();
dep1.setDepartmentId(1L);
dep1.setName("Dep1");
EmbeddedIdExampleEmployeePK key = new EmbeddedIdExampleEmployeePK();
key.setDepartmentId(1L);
key.setEmployeeId(1L);
EmbeddedIdExampleEmployee emp = new EmbeddedIdExampleEmployee();
emp.setDepartment(dep1);
emp.setEmployeePk(key);
emp = employeeRepositoryWithEmbeddedId.save(emp);
key.setDepartmentId(emp.getDepartment().getDepartmentId());
key.setEmployeeId(emp.getEmployeePk().getEmployeeId());
assertThat(employeeRepositoryWithEmbeddedId.exists(key), is(true));
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2008-2013 the original author or authors.
* Copyright 2008-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -40,14 +40,14 @@ import org.springframework.transaction.annotation.Transactional;
* Integration test for {@link JpaRepository}.
*
* @author Oliver Gierke
* @author Thomas Darimont
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({ "classpath:infrastructure.xml" })
@Transactional
public class JpaRepositoryTests {
@PersistenceContext
EntityManager em;
@PersistenceContext EntityManager em;
JpaRepository<SampleEntity, SampleEntityPK> repository;
CrudRepository<SampleWithIdClass, SampleWithIdClassPK> idClassRepository;
@@ -104,6 +104,23 @@ public class JpaRepositoryTests {
assertThat(idClassRepository.exists(new SampleWithIdClassPK(1L, 2L)), is(false));
}
/**
* @see DATAJPA-527
*/
@Test
public void executesExistsForEntityWithIdClass() {
SampleWithIdClass entity = new SampleWithIdClass(1L, 1L);
idClassRepository.save(entity);
assertThat(entity.getFirst(), is(notNullValue()));
assertThat(entity.getSecond(), is(notNullValue()));
SampleWithIdClassPK id = new SampleWithIdClassPK(entity.getFirst(), entity.getSecond());
assertThat(idClassRepository.exists(id), is(true));
}
private static interface SampleEntityRepository extends JpaRepository<SampleEntity, SampleEntityPK> {
}