DATAJDBC-282 - Polishing.

Formatting.
Removed AbstractRelationalEntityWriter.
Fixed integration test for MS-SQL.
Extracted some common test infrastructure.

Original pull request: #107.
This commit is contained in:
Jens Schauder
2019-01-11 11:09:01 +01:00
parent d049988028
commit ff8a71fe62
22 changed files with 917 additions and 774 deletions

View File

@@ -21,106 +21,111 @@ import org.springframework.lang.Nullable;
* Specifies a operations one can perform on a database, based on an <em>Domain Type</em>.
*
* @author Jens Schauder
* @author Thomas Lang
*/
public interface JdbcAggregateOperations {
/**
* Saves an instance of an aggregate, including all the members of the aggregate.
*
* @param instance the aggregate root of the aggregate to be saved. Must not be {@code null}.
* @param <T> the type of the aggregate root.
* @return the saved instance.
*/
<T> T save(T instance);
/**
* Saves an instance of an aggregate, including all the members of the aggregate.
*
* @param instance the aggregate root of the aggregate to be saved. Must not be {@code null}.
* @param <T> the type of the aggregate root.
* @return the saved instance.
*/
<T> T save(T instance);
/**
* Dedicated insert function to do just the insert of an instance of an aggregate, including all the members of the aggregate.
*
* @param instance the aggregate root of the aggregate to be inserted. Must not be {@code null}.
* @param <T> the type of the aggregate root.
* @return the saved instance.
*/
<T> T insert(T instance);
/**
* Dedicated insert function. This skips the test if the aggregate root is new and makes an insert.
* <p>
* This is useful if the client provides an id for new aggregate roots.
* </p>
*
* @param instance the aggregate root of the aggregate to be inserted. Must not be {@code null}.
* @param <T> the type of the aggregate root.
* @return the saved instance.
*/
<T> T insert(T instance);
/**
* Dedicated update function to do just an update of an instance of an aggregate, including all the members of the aggregate.
*
* @param instance the aggregate root of the aggregate to be inserted. Must not be {@code null}.
* @param <T> the type of the aggregate root.
* @return the saved instance.
*/
<T> T update(T instance);
/**
* Dedicated update function. This skips the test if the aggregate root is new or not and always performs an update
* operation.
*
* @param instance the aggregate root of the aggregate to be inserted. Must not be {@code null}.
* @param <T> the type of the aggregate root.
* @return the saved instance.
*/
<T> T update(T instance);
/**
* Deletes a single Aggregate including all entities contained in that aggregate.
*
* @param id the id of the aggregate root of the aggregate to be deleted. Must not be {@code null}.
* @param domainType the type of the aggregate root.
* @param <T> the type of the aggregate root.
*/
<T> void deleteById(Object id, Class<T> domainType);
/**
* Deletes a single Aggregate including all entities contained in that aggregate.
*
* @param id the id of the aggregate root of the aggregate to be deleted. Must not be {@code null}.
* @param domainType the type of the aggregate root.
* @param <T> the type of the aggregate root.
*/
<T> void deleteById(Object id, Class<T> domainType);
/**
* Delete an aggregate identified by it's aggregate root.
*
* @param aggregateRoot to delete. Must not be {@code null}.
* @param domainType the type of the aggregate root. Must not be {@code null}.
* @param <T> the type of the aggregate root.
*/
<T> void delete(T aggregateRoot, Class<T> domainType);
/**
* Delete an aggregate identified by it's aggregate root.
*
* @param aggregateRoot to delete. Must not be {@code null}.
* @param domainType the type of the aggregate root. Must not be {@code null}.
* @param <T> the type of the aggregate root.
*/
<T> void delete(T aggregateRoot, Class<T> domainType);
/**
* Delete all aggregates of a given type.
*
* @param domainType type of the aggregate roots to be deleted. Must not be {@code null}.
*/
void deleteAll(Class<?> domainType);
/**
* Delete all aggregates of a given type.
*
* @param domainType type of the aggregate roots to be deleted. Must not be {@code null}.
*/
void deleteAll(Class<?> domainType);
/**
* Counts the number of aggregates of a given type.
*
* @param domainType the type of the aggregates to be counted.
* @return the number of instances stored in the database. Guaranteed to be not {@code null}.
*/
long count(Class<?> domainType);
/**
* Counts the number of aggregates of a given type.
*
* @param domainType the type of the aggregates to be counted.
* @return the number of instances stored in the database. Guaranteed to be not {@code null}.
*/
long count(Class<?> domainType);
/**
* Load an aggregate from the database.
*
* @param id the id of the aggregate to load. Must not be {@code null}.
* @param domainType the type of the aggregate root. Must not be {@code null}.
* @param <T> the type of the aggregate root.
* @return the loaded aggregate. Might return {@code null}.
*/
@Nullable
<T> T findById(Object id, Class<T> domainType);
/**
* Load an aggregate from the database.
*
* @param id the id of the aggregate to load. Must not be {@code null}.
* @param domainType the type of the aggregate root. Must not be {@code null}.
* @param <T> the type of the aggregate root.
* @return the loaded aggregate. Might return {@code null}.
*/
@Nullable
<T> T findById(Object id, Class<T> domainType);
/**
* Load all aggregates of a given type that are identified by the given ids.
*
* @param ids of the aggregate roots identifying the aggregates to load. Must not be {@code null}.
* @param domainType the type of the aggregate roots. Must not be {@code null}.
* @param <T> the type of the aggregate roots. Must not be {@code null}.
* @return Guaranteed to be not {@code null}.
*/
<T> Iterable<T> findAllById(Iterable<?> ids, Class<T> domainType);
/**
* Load all aggregates of a given type that are identified by the given ids.
*
* @param ids of the aggregate roots identifying the aggregates to load. Must not be {@code null}.
* @param domainType the type of the aggregate roots. Must not be {@code null}.
* @param <T> the type of the aggregate roots. Must not be {@code null}.
* @return Guaranteed to be not {@code null}.
*/
<T> Iterable<T> findAllById(Iterable<?> ids, Class<T> domainType);
/**
* Load all aggregates of a given type.
*
* @param domainType the type of the aggregate roots. Must not be {@code null}.
* @param <T> the type of the aggregate roots. Must not be {@code null}.
* @return Guaranteed to be not {@code null}.
*/
<T> Iterable<T> findAll(Class<T> domainType);
/**
* Load all aggregates of a given type.
*
* @param domainType the type of the aggregate roots. Must not be {@code null}.
* @param <T> the type of the aggregate roots. Must not be {@code null}.
* @return Guaranteed to be not {@code null}.
*/
<T> Iterable<T> findAll(Class<T> domainType);
/**
* Checks if an aggregate identified by type and id exists in the database.
*
* @param id the id of the aggregate root.
* @param domainType the type of the aggregate root.
* @param <T> the type of the aggregate root.
* @return whether the aggregate exists.
*/
<T> boolean existsById(Object id, Class<T> domainType);
/**
* Checks if an aggregate identified by type and id exists in the database.
*
* @param id the id of the aggregate root.
* @param domainType the type of the aggregate root.
* @param <T> the type of the aggregate root.
* @return whether the aggregate exists.
*/
<T> boolean existsById(Object id, Class<T> domainType);
}

View File

@@ -44,6 +44,7 @@ import org.springframework.util.Assert;
*
* @author Jens Schauder
* @author Mark Paluch
* @author Thomas Lang
*/
public class JdbcAggregateTemplate implements JdbcAggregateOperations {
@@ -59,36 +60,12 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
private final DataAccessStrategy accessStrategy;
private <T> T store(T instance, IdentifierAccessor identifierAccessor, AggregateChange<T> change,
RelationalPersistentEntity<?> persistentEntity) {
Assert.notNull(instance, "Aggregate instance must not be null!");
publisher.publishEvent(new BeforeSaveEvent( //
Identifier.ofNullable(identifierAccessor.getIdentifier()), //
instance, //
change //
));
change.executeWith(interpreter, context, converter);
Object identifier = persistentEntity.getIdentifierAccessor(change.getEntity()).getIdentifier();
Assert.notNull(identifier, "After saving the identifier must not be null");
publisher.publishEvent(new AfterSaveEvent( //
Identifier.of(identifier), //
change.getEntity(), //
change //
));
return (T) change.getEntity();
}
/**
* Creates a new {@link JdbcAggregateTemplate} given {@link ApplicationEventPublisher},
* {@link RelationalMappingContext} and {@link DataAccessStrategy}.
*
* @param publisher must not be {@literal null}.
* @param context must not be {@literal null}.
* @param publisher must not be {@literal null}.
* @param context must not be {@literal null}.
* @param dataAccessStrategy must not be {@literal null}.
*/
public JdbcAggregateTemplate(ApplicationEventPublisher publisher, RelationalMappingContext context,
@@ -115,7 +92,8 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
* (non-Javadoc)
* @see org.springframework.data.jdbc.core.JdbcAggregateOperations#save(java.lang.Object)
*/
@Override public <T> T save(T instance) {
@Override
public <T> T save(T instance) {
Assert.notNull(instance, "Aggregate instance must not be null!");
@@ -128,12 +106,15 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
}
/**
* Dedicated insert function to do just the insert of an instance of an aggregate, including all the members of the aggregate.
* Dedicated insert function to do just the insert of an instance of an aggregate, including all the members of the
* aggregate.
*
* @param instance the aggregate root of the aggregate to be inserted. Must not be {@code null}.
* @return the saved instance.
*/
@Override public <T> T insert(T instance) {
@Override
public <T> T insert(T instance) {
Assert.notNull(instance, "Aggregate instance must not be null!");
RelationalPersistentEntity<?> persistentEntity = context.getRequiredPersistentEntity(instance.getClass());
@@ -145,12 +126,15 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
}
/**
* Dedicated update function to do just an update of an instance of an aggregate, including all the members of the aggregate.
* Dedicated update function to do just an update of an instance of an aggregate, including all the members of the
* aggregate.
*
* @param instance the aggregate root of the aggregate to be inserted. Must not be {@code null}.
* @return the saved instance.
*/
@Override public <T> T update(T instance) {
@Override
public <T> T update(T instance) {
Assert.notNull(instance, "Aggregate instance must not be null!");
RelationalPersistentEntity<?> persistentEntity = context.getRequiredPersistentEntity(instance.getClass());
@@ -165,7 +149,8 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
* (non-Javadoc)
* @see org.springframework.data.jdbc.core.JdbcAggregateOperations#count(java.lang.Class)
*/
@Override public long count(Class<?> domainType) {
@Override
public long count(Class<?> domainType) {
return accessStrategy.count(domainType);
}
@@ -173,7 +158,8 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
* (non-Javadoc)
* @see org.springframework.data.jdbc.core.JdbcAggregateOperations#findById(java.lang.Object, java.lang.Class)
*/
@Override public <T> T findById(Object id, Class<T> domainType) {
@Override
public <T> T findById(Object id, Class<T> domainType) {
T entity = accessStrategy.findById(id, domainType);
if (entity != null) {
@@ -186,7 +172,8 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
* (non-Javadoc)
* @see org.springframework.data.jdbc.core.JdbcAggregateOperations#existsById(java.lang.Object, java.lang.Class)
*/
@Override public <T> boolean existsById(Object id, Class<T> domainType) {
@Override
public <T> boolean existsById(Object id, Class<T> domainType) {
return accessStrategy.existsById(id, domainType);
}
@@ -194,7 +181,8 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
* (non-Javadoc)
* @see org.springframework.data.jdbc.core.JdbcAggregateOperations#findAll(java.lang.Class)
*/
@Override public <T> Iterable<T> findAll(Class<T> domainType) {
@Override
public <T> Iterable<T> findAll(Class<T> domainType) {
Iterable<T> all = accessStrategy.findAll(domainType);
publishAfterLoad(all);
@@ -205,7 +193,8 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
* (non-Javadoc)
* @see org.springframework.data.jdbc.core.JdbcAggregateOperations#findAllById(java.lang.Iterable, java.lang.Class)
*/
@Override public <T> Iterable<T> findAllById(Iterable<?> ids, Class<T> domainType) {
@Override
public <T> Iterable<T> findAllById(Iterable<?> ids, Class<T> domainType) {
Iterable<T> allById = accessStrategy.findAllById(ids, domainType);
publishAfterLoad(allById);
@@ -216,7 +205,8 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
* (non-Javadoc)
* @see org.springframework.data.jdbc.core.JdbcAggregateOperations#delete(java.lang.Object, java.lang.Class)
*/
@Override public <S> void delete(S aggregateRoot, Class<S> domainType) {
@Override
public <S> void delete(S aggregateRoot, Class<S> domainType) {
IdentifierAccessor identifierAccessor = context.getRequiredPersistentEntity(domainType)
.getIdentifierAccessor(aggregateRoot);
@@ -228,7 +218,8 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
* (non-Javadoc)
* @see org.springframework.data.jdbc.core.JdbcAggregateOperations#deleteById(java.lang.Object, java.lang.Class)
*/
@Override public <S> void deleteById(Object id, Class<S> domainType) {
@Override
public <S> void deleteById(Object id, Class<S> domainType) {
deleteTree(id, null, domainType);
}
@@ -236,12 +227,39 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
* (non-Javadoc)
* @see org.springframework.data.jdbc.core.JdbcAggregateOperations#deleteAll(java.lang.Class)
*/
@Override public void deleteAll(Class<?> domainType) {
@Override
public void deleteAll(Class<?> domainType) {
AggregateChange<?> change = createDeletingChange(domainType);
change.executeWith(interpreter, context, converter);
}
private <T> T store(T instance, IdentifierAccessor identifierAccessor, AggregateChange<T> change,
RelationalPersistentEntity<?> persistentEntity) {
Assert.notNull(instance, "Aggregate instance must not be null!");
publisher.publishEvent(new BeforeSaveEvent( //
Identifier.ofNullable(identifierAccessor.getIdentifier()), //
instance, //
change //
));
change.executeWith(interpreter, context, converter);
Object identifier = persistentEntity.getIdentifierAccessor(change.getEntity()).getIdentifier();
Assert.notNull(identifier, "After saving the identifier must not be null");
publisher.publishEvent(new AfterSaveEvent( //
Identifier.of(identifier), //
change.getEntity(), //
change //
));
return (T) change.getEntity();
}
private void deleteTree(Object id, @Nullable Object entity, Class<?> domainType) {
AggregateChange<?> change = createDeletingChange(id, entity, domainType);
@@ -255,21 +273,24 @@ public class JdbcAggregateTemplate implements JdbcAggregateOperations {
publisher.publishEvent(new AfterDeleteEvent(specifiedId, optionalEntity, change));
}
@SuppressWarnings({ "unchecked", "rawtypes" }) private <T> AggregateChange<T> createChange(T instance) {
@SuppressWarnings({ "unchecked", "rawtypes" })
private <T> AggregateChange<T> createChange(T instance) {
AggregateChange<T> aggregateChange = new AggregateChange(Kind.SAVE, instance.getClass(), instance);
jdbcEntityWriter.write(instance, aggregateChange);
return aggregateChange;
}
@SuppressWarnings({ "unchecked", "rawtypes" }) private <T> AggregateChange<T> createInsertChange(T instance) {
@SuppressWarnings({ "unchecked", "rawtypes" })
private <T> AggregateChange<T> createInsertChange(T instance) {
AggregateChange<T> aggregateChange = new AggregateChange(Kind.SAVE, instance.getClass(), instance);
jdbcEntityInsertWriter.write(instance, aggregateChange);
return aggregateChange;
}
@SuppressWarnings({ "unchecked", "rawtypes" }) private <T> AggregateChange<T> createUpdateChange(T instance) {
@SuppressWarnings({ "unchecked", "rawtypes" })
private <T> AggregateChange<T> createUpdateChange(T instance) {
AggregateChange<T> aggregateChange = new AggregateChange(Kind.SAVE, instance.getClass(), instance);
jdbcEntityUpdateWriter.write(instance, aggregateChange);

View File

@@ -3,16 +3,36 @@ package org.springframework.data.jdbc.core;
import org.springframework.data.repository.Repository;
/**
* Jdbc repository for dedicated insert(), update() and upsert() sql functions.
* Other than {@link org.springframework.data.jdbc.repository.support.SimpleJdbcRepository}
* there should be bypassing of the isNew check.
* Jdbc repository for dedicated insert(), update() and upsert() sql functions. Other than
* {@link org.springframework.data.jdbc.repository.support.SimpleJdbcRepository} there should be bypassing of the isNew
* check.
*
* @author Thomas Lang
* @see <a href="https://jira.spring.io/browse/DATAJDBC-282">DATAJDBC-282</a>
* @since 1.1
*/
public interface JdbcRepository<T, ID> extends Repository<T, ID> {
<S extends T> S insert(S var1);
/**
* Dedicated insert function. This skips the test if the aggregate root is new and makes an insert.
* <p>
* This is useful if the client provides an id for new aggregate roots.
* </p>
*
* @param aggregateRoot the aggregate root to be saved in the database. Must not be {@code null}.
* @param <S> Type of the aggregate root.
* @return the saved aggregate root. If the provided aggregate root was immutable and a value needed changing, e.g.
* the id this will be a new instance.
*/
<S extends T> S insert(S aggregateRoot);
<S extends T> S update(S var1);
/**
* Dedicated update function. This skips the test if the aggregate root is new or not and always performs an update
* operation.
*
* @param aggregateRoot the aggregate root to be saved in the database. Must not be {@code null}.
* @param <S> Type of the aggregate root.
* @return the saved aggregate root. If the provided aggregate root was immutable and a value needed changing, e.g.
* the id this will be a new instance.
*/
<S extends T> S update(S aggregateRoot);
}

View File

@@ -152,7 +152,7 @@ public class SimpleJdbcRepository<T, ID> implements CrudRepository<T, ID>, JdbcR
* @see org.springframework.data.repository.JdbcRepository#update(T t)
*/
@Override
public <S extends T> S update(S var1) {
return entityOperations.update(var1);
public <S extends T> S update(S aggregateRoot) {
return entityOperations.update(aggregateRoot);
}
}

View File

@@ -0,0 +1,102 @@
/*
* Copyright 2017-2019 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.jdbc.repository;
import static org.assertj.core.api.Assertions.*;
import lombok.Data;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.annotation.Id;
import org.springframework.data.jdbc.core.JdbcRepository;
import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory;
import org.springframework.data.jdbc.testing.TestConfiguration;
import org.springframework.data.repository.CrudRepository;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.rules.SpringClassRule;
import org.springframework.test.context.junit4.rules.SpringMethodRule;
import org.springframework.test.jdbc.JdbcTestUtils;
import org.springframework.transaction.annotation.Transactional;
/**
* Very simple use cases for creation and usage of JdbcRepositories.
*
* @author Jens Schauder
*/
@ContextConfiguration
@Transactional
public class JdbcRepositoryInsertExistingIntegrationTests {
@Configuration
@Import(TestConfiguration.class)
static class Config {
@Autowired JdbcRepositoryFactory factory;
@Bean
Class<?> testClass() {
return JdbcRepositoryInsertExistingIntegrationTests.class;
}
@Bean
DummyEntityRepository dummyEntityRepository() {
return factory.getRepository(DummyEntityRepository.class);
}
}
@ClassRule public static final SpringClassRule classRule = new SpringClassRule();
@Rule public SpringMethodRule methodRule = new SpringMethodRule();
@Autowired NamedParameterJdbcTemplate template;
@Autowired DummyEntityRepository repository;
@Test // DATAJDBC-282
public void insertAnExistingEntity() {
DummyEntity existingDummyEntity = createDummyEntity();
existingDummyEntity.idProp = 123L;
DummyEntity entity = repository.insert(existingDummyEntity);
assertThat(JdbcTestUtils.countRowsInTableWhere((JdbcTemplate) template.getJdbcOperations(), "dummy_entity",
"id_Prop = " + existingDummyEntity.getIdProp())).isEqualTo(1);
}
private static DummyEntity createDummyEntity() {
DummyEntity entity = new DummyEntity();
entity.setName("Entity Name");
return entity;
}
interface DummyEntityRepository extends CrudRepository<DummyEntity, Long>, JdbcRepository<DummyEntity, Long> {}
@Data
static class DummyEntity {
String name;
@Id private Long idProp;
}
}

View File

@@ -40,6 +40,8 @@ import org.springframework.test.context.junit4.rules.SpringMethodRule;
import org.springframework.test.jdbc.JdbcTestUtils;
import org.springframework.transaction.annotation.Transactional;
import java.util.HashMap;
/**
* Very simple use cases for creation and usage of JdbcRepositories.
*
@@ -49,246 +51,222 @@ import org.springframework.transaction.annotation.Transactional;
@Transactional
public class JdbcRepositoryIntegrationTests {
@Configuration
@Import(TestConfiguration.class)
static class Config {
@Configuration
@Import(TestConfiguration.class)
static class Config {
@Autowired
JdbcRepositoryFactory factory;
@Autowired JdbcRepositoryFactory factory;
@Bean
Class<?> testClass() {
return JdbcRepositoryIntegrationTests.class;
}
@Bean
Class<?> testClass() {
return JdbcRepositoryIntegrationTests.class;
}
@Bean
DummyEntityRepository dummyEntityRepository() {
return factory.getRepository(DummyEntityRepository.class);
}
@Bean
DummyEntityRepository dummyEntityRepository() {
return factory.getRepository(DummyEntityRepository.class);
}
}
}
@ClassRule
public static final SpringClassRule classRule = new SpringClassRule();
@Rule
public SpringMethodRule methodRule = new SpringMethodRule();
@ClassRule public static final SpringClassRule classRule = new SpringClassRule();
@Rule public SpringMethodRule methodRule = new SpringMethodRule();
@Autowired
NamedParameterJdbcTemplate template;
@Autowired
DummyEntityRepository repository;
@Autowired NamedParameterJdbcTemplate template;
@Autowired DummyEntityRepository repository;
@Test // DATAJDBC-95
public void savesAnEntity() {
@Test // DATAJDBC-95
public void savesAnEntity() {
DummyEntity entity = repository.save(createDummyEntity());
DummyEntity entity = repository.save(createDummyEntity());
assertThat(JdbcTestUtils.countRowsInTableWhere((JdbcTemplate) template.getJdbcOperations(), "dummy_entity",
"id_Prop = " + entity.getIdProp())).isEqualTo(1);
}
assertThat(JdbcTestUtils.countRowsInTableWhere((JdbcTemplate) template.getJdbcOperations(), "dummy_entity",
"id_Prop = " + entity.getIdProp())).isEqualTo(1);
}
@Test // DATAJDBC-282
public void insertAnEntity() {
@Test // DATAJDBC-282
public void insertAnEntity() {
DummyEntity entity = repository.insert(createDummyEntity());
DummyEntity entity = repository.insert(createDummyEntity());
assertThat(JdbcTestUtils.countRowsInTableWhere((JdbcTemplate) template.getJdbcOperations(), "dummy_entity",
"id_Prop = " + entity.getIdProp())).isEqualTo(1);
}
assertThat(JdbcTestUtils.countRowsInTableWhere((JdbcTemplate) template.getJdbcOperations(), "dummy_entity",
"id_Prop = " + entity.getIdProp())).isEqualTo(1);
}
@Test // DATAJDBC-282
public void insertAnExistingEntity() {
@Test // DATAJDBC-95
public void saveAndLoadAnEntity() {
DummyEntity existingDummyEntity = createExistingDummyEntity();
DummyEntity entity = repository.insert(existingDummyEntity);
assertThat(JdbcTestUtils.countRowsInTableWhere((JdbcTemplate) template.getJdbcOperations(), "dummy_entity",
"id_Prop = " + existingDummyEntity.getIdProp())).isEqualTo(1);
}
DummyEntity entity = repository.save(createDummyEntity());
@Test // DATAJDBC-95
public void saveAndLoadAnEntity() {
assertThat(repository.findById(entity.getIdProp())).hasValueSatisfying(it -> {
DummyEntity entity = repository.save(createDummyEntity());
assertThat(it.getIdProp()).isEqualTo(entity.getIdProp());
assertThat(it.getName()).isEqualTo(entity.getName());
});
}
assertThat(repository.findById(entity.getIdProp())).hasValueSatisfying(it -> {
@Test // DATAJDBC-97
public void savesManyEntities() {
assertThat(it.getIdProp()).isEqualTo(entity.getIdProp());
assertThat(it.getName()).isEqualTo(entity.getName());
});
}
DummyEntity entity = createDummyEntity();
DummyEntity other = createDummyEntity();
@Test // DATAJDBC-97
public void savesManyEntities() {
repository.saveAll(asList(entity, other));
DummyEntity entity = createDummyEntity();
DummyEntity other = createDummyEntity();
assertThat(repository.findAll()) //
.extracting(DummyEntity::getIdProp) //
.containsExactlyInAnyOrder(entity.getIdProp(), other.getIdProp());
}
repository.saveAll(asList(entity, other));
@Test // DATAJDBC-97
public void existsReturnsTrueIffEntityExists() {
assertThat(repository.findAll()) //
.extracting(DummyEntity::getIdProp) //
.containsExactlyInAnyOrder(entity.getIdProp(), other.getIdProp());
}
DummyEntity entity = repository.save(createDummyEntity());
@Test // DATAJDBC-97
public void existsReturnsTrueIffEntityExists() {
assertThat(repository.existsById(entity.getIdProp())).isTrue();
assertThat(repository.existsById(entity.getIdProp() + 1)).isFalse();
}
DummyEntity entity = repository.save(createDummyEntity());
@Test // DATAJDBC-97
public void findAllFindsAllEntities() {
assertThat(repository.existsById(entity.getIdProp())).isTrue();
assertThat(repository.existsById(entity.getIdProp() + 1)).isFalse();
}
DummyEntity entity = repository.save(createDummyEntity());
DummyEntity other = repository.save(createDummyEntity());
@Test // DATAJDBC-97
public void findAllFindsAllEntities() {
Iterable<DummyEntity> all = repository.findAll();
DummyEntity entity = repository.save(createDummyEntity());
DummyEntity other = repository.save(createDummyEntity());
assertThat(all)//
.extracting(DummyEntity::getIdProp)//
.containsExactlyInAnyOrder(entity.getIdProp(), other.getIdProp());
}
Iterable<DummyEntity> all = repository.findAll();
@Test // DATAJDBC-97
public void findAllFindsAllSpecifiedEntities() {
assertThat(all)//
.extracting(DummyEntity::getIdProp)//
.containsExactlyInAnyOrder(entity.getIdProp(), other.getIdProp());
}
DummyEntity entity = repository.save(createDummyEntity());
DummyEntity other = repository.save(createDummyEntity());
@Test // DATAJDBC-97
public void findAllFindsAllSpecifiedEntities() {
assertThat(repository.findAllById(asList(entity.getIdProp(), other.getIdProp())))//
.extracting(DummyEntity::getIdProp)//
.containsExactlyInAnyOrder(entity.getIdProp(), other.getIdProp());
}
DummyEntity entity = repository.save(createDummyEntity());
DummyEntity other = repository.save(createDummyEntity());
@Test // DATAJDBC-97
public void countsEntities() {
assertThat(repository.findAllById(asList(entity.getIdProp(), other.getIdProp())))//
.extracting(DummyEntity::getIdProp)//
.containsExactlyInAnyOrder(entity.getIdProp(), other.getIdProp());
}
repository.save(createDummyEntity());
repository.save(createDummyEntity());
repository.save(createDummyEntity());
@Test // DATAJDBC-97
public void countsEntities() {
assertThat(repository.count()).isEqualTo(3L);
}
repository.save(createDummyEntity());
repository.save(createDummyEntity());
repository.save(createDummyEntity());
@Test // DATAJDBC-97
public void deleteById() {
assertThat(repository.count()).isEqualTo(3L);
}
DummyEntity one = repository.save(createDummyEntity());
DummyEntity two = repository.save(createDummyEntity());
DummyEntity three = repository.save(createDummyEntity());
@Test // DATAJDBC-97
public void deleteById() {
repository.deleteById(two.getIdProp());
DummyEntity one = repository.save(createDummyEntity());
DummyEntity two = repository.save(createDummyEntity());
DummyEntity three = repository.save(createDummyEntity());
assertThat(repository.findAll()) //
.extracting(DummyEntity::getIdProp) //
.containsExactlyInAnyOrder(one.getIdProp(), three.getIdProp());
}
repository.deleteById(two.getIdProp());
@Test // DATAJDBC-97
public void deleteByEntity() {
assertThat(repository.findAll()) //
.extracting(DummyEntity::getIdProp) //
.containsExactlyInAnyOrder(one.getIdProp(), three.getIdProp());
}
DummyEntity one = repository.save(createDummyEntity());
DummyEntity two = repository.save(createDummyEntity());
DummyEntity three = repository.save(createDummyEntity());
@Test // DATAJDBC-97
public void deleteByEntity() {
repository.delete(one);
DummyEntity one = repository.save(createDummyEntity());
DummyEntity two = repository.save(createDummyEntity());
DummyEntity three = repository.save(createDummyEntity());
assertThat(repository.findAll()) //
.extracting(DummyEntity::getIdProp) //
.containsExactlyInAnyOrder(two.getIdProp(), three.getIdProp());
}
repository.delete(one);
@Test // DATAJDBC-97
public void deleteByList() {
assertThat(repository.findAll()) //
.extracting(DummyEntity::getIdProp) //
.containsExactlyInAnyOrder(two.getIdProp(), three.getIdProp());
}
DummyEntity one = repository.save(createDummyEntity());
DummyEntity two = repository.save(createDummyEntity());
DummyEntity three = repository.save(createDummyEntity());
@Test // DATAJDBC-97
public void deleteByList() {
repository.deleteAll(asList(one, three));
DummyEntity one = repository.save(createDummyEntity());
DummyEntity two = repository.save(createDummyEntity());
DummyEntity three = repository.save(createDummyEntity());
assertThat(repository.findAll()) //
.extracting(DummyEntity::getIdProp) //
.containsExactlyInAnyOrder(two.getIdProp());
}
repository.deleteAll(asList(one, three));
@Test // DATAJDBC-97
public void deleteAll() {
assertThat(repository.findAll()) //
.extracting(DummyEntity::getIdProp) //
.containsExactlyInAnyOrder(two.getIdProp());
}
repository.save(createDummyEntity());
repository.save(createDummyEntity());
repository.save(createDummyEntity());
@Test // DATAJDBC-97
public void deleteAll() {
assertThat(repository.findAll()).isNotEmpty();
repository.save(createDummyEntity());
repository.save(createDummyEntity());
repository.save(createDummyEntity());
repository.deleteAll();
assertThat(repository.findAll()).isNotEmpty();
assertThat(repository.findAll()).isEmpty();
}
repository.deleteAll();
@Test // DATAJDBC-98
public void update() {
assertThat(repository.findAll()).isEmpty();
}
DummyEntity entity = repository.save(createDummyEntity());
@Test // DATAJDBC-98
public void update() {
entity.setName("something else");
DummyEntity saved = repository.save(entity);
DummyEntity entity = repository.save(createDummyEntity());
assertThat(repository.findById(entity.getIdProp())).hasValueSatisfying(it -> {
assertThat(it.getName()).isEqualTo(saved.getName());
});
}
entity.setName("something else");
DummyEntity saved = repository.save(entity);
@Test // DATAJDBC-98
public void updateMany() {
assertThat(repository.findById(entity.getIdProp())).hasValueSatisfying(it -> {
assertThat(it.getName()).isEqualTo(saved.getName());
});
}
DummyEntity entity = repository.save(createDummyEntity());
DummyEntity other = repository.save(createDummyEntity());
@Test // DATAJDBC-98
public void updateMany() {
entity.setName("something else");
other.setName("others Name");
DummyEntity entity = repository.save(createDummyEntity());
DummyEntity other = repository.save(createDummyEntity());
repository.saveAll(asList(entity, other));
entity.setName("something else");
other.setName("others Name");
assertThat(repository.findAll()) //
.extracting(DummyEntity::getName) //
.containsExactlyInAnyOrder(entity.getName(), other.getName());
}
repository.saveAll(asList(entity, other));
@Test // DATAJDBC-112
public void findByIdReturnsEmptyWhenNoneFound() {
assertThat(repository.findAll()) //
.extracting(DummyEntity::getName) //
.containsExactlyInAnyOrder(entity.getName(), other.getName());
}
// NOT saving anything, so DB is empty
@Test // DATAJDBC-112
public void findByIdReturnsEmptyWhenNoneFound() {
assertThat(repository.findById(-1L)).isEmpty();
}
// NOT saving anything, so DB is empty
private static DummyEntity createDummyEntity() {
assertThat(repository.findById(-1L)).isEmpty();
}
DummyEntity entity = new DummyEntity();
entity.setName("Entity Name");
return entity;
}
private static DummyEntity createDummyEntity() {
interface DummyEntityRepository extends CrudRepository<DummyEntity, Long>, JdbcRepository<DummyEntity, Long> {}
DummyEntity entity = new DummyEntity();
entity.setName("Entity Name");
return entity;
}
@Data
static class DummyEntity {
private static DummyEntity createExistingDummyEntity() {
DummyEntity entity = new DummyEntity();
entity.setIdProp(Long.parseLong("123"));
entity.setName("Entity Name");
return entity;
}
interface DummyEntityRepository extends CrudRepository<DummyEntity, Long>, JdbcRepository<DummyEntity, Long> {
}
@Data
static class DummyEntity {
String name;
@Id
private Long idProp;
}
String name;
@Id private Long idProp;
}
}

View File

@@ -0,0 +1 @@
CREATE TABLE dummy_entity ( id_Prop BIGINT PRIMARY KEY, NAME VARCHAR(100))

View File

@@ -0,0 +1 @@
CREATE TABLE dummy_entity (id_Prop BIGINT PRIMARY KEY, NAME VARCHAR(100));

View File

@@ -0,0 +1,2 @@
DROP TABLE IF EXISTS dummy_entity;
CREATE TABLE dummy_entity (id_Prop BIGINT PRIMARY KEY, NAME VARCHAR(100));

View File

@@ -0,0 +1 @@
CREATE TABLE dummy_entity (id_Prop BIGINT PRIMARY KEY, NAME VARCHAR(100));

View File

@@ -0,0 +1,2 @@
DROP TABLE dummy_entity;
CREATE TABLE dummy_entity (id_Prop INTEGER PRIMARY KEY, NAME VARCHAR(100));