Polishing.
Fix merge problems. Execute tests only for HsqlDb. Refactoring to use lists instead of streams. We try to avoid the latter, since they are prone to cause performance issues. Minor refactorings. See #771 See #230 Original pull request #1486
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020 the original author or authors.
|
||||
* Copyright 2020-2024 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,10 +22,11 @@ import java.util.stream.Stream;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.jdbc.core.convert.JdbcConverter;
|
||||
import org.springframework.data.jdbc.core.convert.QueryMapper;
|
||||
import org.springframework.data.mapping.Parameter;
|
||||
import org.springframework.data.mapping.PersistentPropertyPath;
|
||||
import org.springframework.data.relational.core.dialect.Dialect;
|
||||
import org.springframework.data.relational.core.dialect.RenderContextFactory;
|
||||
import org.springframework.data.relational.core.mapping.PersistentPropertyPathExtension;
|
||||
import org.springframework.data.relational.core.mapping.AggregatePath;
|
||||
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
|
||||
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
|
||||
@@ -48,102 +49,110 @@ import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Implementation of {@link RelationalQueryCreator} that creates {@link Stream} of deletion {@link ParametrizedQuery}
|
||||
* Implementation of {@link RelationalQueryCreator} that creates {@link List} of deletion {@link ParametrizedQuery}
|
||||
* from a {@link PartTree}.
|
||||
*
|
||||
* @author Yunyoung LEE
|
||||
* @since 2.3
|
||||
* @author Nikita Konev
|
||||
* @since 3.5
|
||||
*/
|
||||
class JdbcDeleteQueryCreator extends RelationalQueryCreator<Stream<ParametrizedQuery>> {
|
||||
class JdbcDeleteQueryCreator extends RelationalQueryCreator<List<ParametrizedQuery>> {
|
||||
|
||||
private final RelationalMappingContext context;
|
||||
private final QueryMapper queryMapper;
|
||||
private final RelationalEntityMetadata<?> entityMetadata;
|
||||
private final RenderContextFactory renderContextFactory;
|
||||
private final RelationalMappingContext context;
|
||||
private final QueryMapper queryMapper;
|
||||
private final RelationalEntityMetadata<?> entityMetadata;
|
||||
private final RenderContextFactory renderContextFactory;
|
||||
|
||||
/**
|
||||
* Creates new instance of this class with the given {@link PartTree}, {@link JdbcConverter}, {@link Dialect},
|
||||
* {@link RelationalEntityMetadata} and {@link RelationalParameterAccessor}.
|
||||
*
|
||||
* @param context
|
||||
* @param tree part tree, must not be {@literal null}.
|
||||
* @param converter must not be {@literal null}.
|
||||
* @param dialect must not be {@literal null}.
|
||||
* @param entityMetadata relational entity metadata, must not be {@literal null}.
|
||||
* @param accessor parameter metadata provider, must not be {@literal null}.
|
||||
*/
|
||||
JdbcDeleteQueryCreator(RelationalMappingContext context, PartTree tree, JdbcConverter converter, Dialect dialect,
|
||||
RelationalEntityMetadata<?> entityMetadata, RelationalParameterAccessor accessor) {
|
||||
super(tree, accessor);
|
||||
/**
|
||||
* Creates new instance of this class with the given {@link PartTree}, {@link JdbcConverter}, {@link Dialect},
|
||||
* {@link RelationalEntityMetadata} and {@link RelationalParameterAccessor}.
|
||||
*
|
||||
* @param context
|
||||
* @param tree part tree, must not be {@literal null}.
|
||||
* @param converter must not be {@literal null}.
|
||||
* @param dialect must not be {@literal null}.
|
||||
* @param entityMetadata relational entity metadata, must not be {@literal null}.
|
||||
* @param accessor parameter metadata provider, must not be {@literal null}.
|
||||
*/
|
||||
JdbcDeleteQueryCreator(RelationalMappingContext context, PartTree tree, JdbcConverter converter, Dialect dialect,
|
||||
RelationalEntityMetadata<?> entityMetadata, RelationalParameterAccessor accessor) {
|
||||
|
||||
Assert.notNull(converter, "JdbcConverter must not be null");
|
||||
Assert.notNull(dialect, "Dialect must not be null");
|
||||
Assert.notNull(entityMetadata, "Relational entity metadata must not be null");
|
||||
super(tree, accessor);
|
||||
|
||||
this.context = context;
|
||||
Assert.notNull(converter, "JdbcConverter must not be null");
|
||||
Assert.notNull(dialect, "Dialect must not be null");
|
||||
Assert.notNull(entityMetadata, "Relational entity metadata must not be null");
|
||||
|
||||
this.entityMetadata = entityMetadata;
|
||||
this.queryMapper = new QueryMapper(dialect, converter);
|
||||
this.renderContextFactory = new RenderContextFactory(dialect);
|
||||
}
|
||||
this.context = context;
|
||||
this.entityMetadata = entityMetadata;
|
||||
this.queryMapper = new QueryMapper(converter);
|
||||
this.renderContextFactory = new RenderContextFactory(dialect);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Stream<ParametrizedQuery> complete(@Nullable Criteria criteria, Sort sort) {
|
||||
@Override
|
||||
protected List<ParametrizedQuery> complete(@Nullable Criteria criteria, Sort sort) {
|
||||
|
||||
RelationalPersistentEntity<?> entity = entityMetadata.getTableEntity();
|
||||
Table table = Table.create(entityMetadata.getTableName());
|
||||
MapSqlParameterSource parameterSource = new MapSqlParameterSource();
|
||||
RelationalPersistentEntity<?> entity = entityMetadata.getTableEntity();
|
||||
Table table = Table.create(entityMetadata.getTableName());
|
||||
MapSqlParameterSource parameterSource = new MapSqlParameterSource();
|
||||
|
||||
SqlContext sqlContext = new SqlContext(entity);
|
||||
SqlContext sqlContext = new SqlContext(entity);
|
||||
|
||||
Condition condition = criteria == null ? null
|
||||
: queryMapper.getMappedObject(parameterSource, criteria, table, entity);
|
||||
Condition condition = criteria == null ? null
|
||||
: queryMapper.getMappedObject(parameterSource, criteria, table, entity);
|
||||
|
||||
// create select criteria query for subselect
|
||||
SelectWhere selectBuilder = StatementBuilder.select(sqlContext.getIdColumn()).from(table);
|
||||
Select select = condition == null ? selectBuilder.build() : selectBuilder.where(condition).build();
|
||||
// create select criteria query for subselect
|
||||
SelectWhere selectBuilder = StatementBuilder.select(sqlContext.getIdColumn()).from(table);
|
||||
Select select = condition == null ? selectBuilder.build() : selectBuilder.where(condition).build();
|
||||
|
||||
// create delete relation queries
|
||||
List<Delete> deleteChain = new ArrayList<>();
|
||||
deleteRelations(deleteChain, entity, select);
|
||||
// create delete relation queries
|
||||
List<Delete> deleteChain = new ArrayList<>();
|
||||
deleteRelations(deleteChain, entity, select);
|
||||
|
||||
// crate delete query
|
||||
DeleteWhere deleteBuilder = StatementBuilder.delete(table);
|
||||
Delete delete = condition == null ? deleteBuilder.build() : deleteBuilder.where(condition).build();
|
||||
// crate delete query
|
||||
DeleteWhere deleteBuilder = StatementBuilder.delete(table);
|
||||
Delete delete = condition == null ? deleteBuilder.build() : deleteBuilder.where(condition).build();
|
||||
|
||||
deleteChain.add(delete);
|
||||
deleteChain.add(delete);
|
||||
|
||||
SqlRenderer renderer = SqlRenderer.create(renderContextFactory.createRenderContext());
|
||||
return deleteChain.stream().map(d -> new ParametrizedQuery(renderer.render(d), parameterSource));
|
||||
}
|
||||
SqlRenderer renderer = SqlRenderer.create(renderContextFactory.createRenderContext());
|
||||
|
||||
private void deleteRelations(List<Delete> deleteChain, RelationalPersistentEntity<?> entity, Select parentSelect) {
|
||||
List<ParametrizedQuery> queries = new ArrayList<>(deleteChain.size());
|
||||
for (Delete d : deleteChain) {
|
||||
queries.add(new ParametrizedQuery(renderer.render(d), parameterSource));
|
||||
}
|
||||
|
||||
for (PersistentPropertyPath<RelationalPersistentProperty> path : context
|
||||
.findPersistentPropertyPaths(entity.getType(), p -> true)) {
|
||||
return queries;
|
||||
}
|
||||
|
||||
PersistentPropertyPathExtension extPath = new PersistentPropertyPathExtension(context, path);
|
||||
private void deleteRelations(List<Delete> deleteChain, RelationalPersistentEntity<?> entity, Select parentSelect) {
|
||||
|
||||
// prevent duplication on recursive call
|
||||
if (path.getLength() > 1 && !extPath.getParentPath().isEmbedded()) {
|
||||
continue;
|
||||
}
|
||||
for (PersistentPropertyPath<RelationalPersistentProperty> path : context
|
||||
.findPersistentPropertyPaths(entity.getType(), p -> true)) {
|
||||
|
||||
if (extPath.isEntity() && !extPath.isEmbedded()) {
|
||||
AggregatePath aggregatePath = context.getAggregatePath(path);
|
||||
|
||||
SqlContext sqlContext = new SqlContext(extPath.getLeafEntity());
|
||||
// prevent duplication on recursive call
|
||||
if (path.getLength() > 1 && !aggregatePath.getParentPath().isEmbedded()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Condition inCondition = Conditions.in(sqlContext.getTable().column(extPath.getReverseColumnName()),
|
||||
parentSelect);
|
||||
if (aggregatePath.isEntity() && !aggregatePath.isEmbedded()) {
|
||||
|
||||
Select select = StatementBuilder
|
||||
.select(sqlContext.getTable().column(extPath.getIdDefiningParentPath().getIdColumnName())
|
||||
// sqlContext.getIdColumn()
|
||||
).from(sqlContext.getTable()).where(inCondition).build();
|
||||
deleteRelations(deleteChain, extPath.getLeafEntity(), select);
|
||||
SqlContext sqlContext = new SqlContext(aggregatePath.getLeafEntity());
|
||||
|
||||
deleteChain.add(StatementBuilder.delete(sqlContext.getTable()).where(inCondition).build());
|
||||
}
|
||||
}
|
||||
}
|
||||
Condition inCondition = Conditions
|
||||
.in(sqlContext.getTable().column(aggregatePath.getTableInfo().reverseColumnInfo().name()), parentSelect);
|
||||
|
||||
Select select = StatementBuilder.select( //
|
||||
sqlContext.getTable().column(aggregatePath.getIdDefiningParentPath().getTableInfo().idColumnName()) //
|
||||
).from(sqlContext.getTable()) //
|
||||
.where(inCondition) //
|
||||
.build();
|
||||
deleteRelations(deleteChain, aggregatePath.getLeafEntity(), select);
|
||||
|
||||
deleteChain.add(StatementBuilder.delete(sqlContext.getTable()).where(inCondition).build());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,8 +23,8 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.LongSupplier;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
@@ -58,6 +58,8 @@ import org.springframework.util.Assert;
|
||||
* @author Jens Schauder
|
||||
* @author Diego Krupitza
|
||||
* @author Mikhail Polivakha
|
||||
* @author Yunyoung LEE
|
||||
* @author Nikita Konev
|
||||
* @since 2.0
|
||||
*/
|
||||
public class PartTreeJdbcQuery extends AbstractJdbcQuery {
|
||||
@@ -123,17 +125,23 @@ public class PartTreeJdbcQuery extends AbstractJdbcQuery {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Object execute(Object[] values) {
|
||||
|
||||
RelationalParametersParameterAccessor accessor = new RelationalParametersParameterAccessor(getQueryMethod(),
|
||||
values);
|
||||
|
||||
if (tree.isDelete()) {
|
||||
JdbcQueryExecution<?> execution = createModifyingQueryExecutor();
|
||||
return createDeleteQueries(accessor)
|
||||
.map(query -> execution.execute(query.getQuery(), query.getParameterSource()))
|
||||
.reduce((a, b) -> b);
|
||||
}
|
||||
if (tree.isDelete()) {
|
||||
JdbcQueryExecution<?> execution = createModifyingQueryExecutor();
|
||||
|
||||
List<ParametrizedQuery> queries = createDeleteQueries(accessor);
|
||||
Object result = null;
|
||||
for (ParametrizedQuery query : queries) {
|
||||
result = execution.execute(query.getQuery(), query.getParameterSource(dialect.getLikeEscaper()));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ResultProcessor processor = getQueryMethod().getResultProcessor().withDynamicProjection(accessor);
|
||||
ParametrizedQuery query = createQuery(accessor, processor.getReturnedType());
|
||||
@@ -153,11 +161,13 @@ public class PartTreeJdbcQuery extends AbstractJdbcQuery {
|
||||
JdbcQueryExecution<?> queryExecution = getJdbcQueryExecution(extractor, rowMapper);
|
||||
|
||||
if (getQueryMethod().isSliceQuery()) {
|
||||
//noinspection unchecked
|
||||
return new SliceQueryExecution<>((JdbcQueryExecution<Collection<Object>>) queryExecution, accessor.getPageable());
|
||||
}
|
||||
|
||||
if (getQueryMethod().isPageQuery()) {
|
||||
|
||||
//noinspection unchecked
|
||||
return new PageQueryExecution<>((JdbcQueryExecution<Collection<Object>>) queryExecution, accessor.getPageable(),
|
||||
() -> {
|
||||
|
||||
@@ -186,14 +196,14 @@ public class PartTreeJdbcQuery extends AbstractJdbcQuery {
|
||||
return queryCreator.createQuery(getDynamicSort(accessor));
|
||||
}
|
||||
|
||||
private Stream<ParametrizedQuery> createDeleteQueries(RelationalParametersParameterAccessor accessor) {
|
||||
private List<ParametrizedQuery> createDeleteQueries(RelationalParametersParameterAccessor accessor) {
|
||||
|
||||
RelationalEntityMetadata<?> entityMetadata = getQueryMethod().getEntityInformation();
|
||||
RelationalEntityMetadata<?> entityMetadata = getQueryMethod().getEntityInformation();
|
||||
|
||||
JdbcDeleteQueryCreator queryCreator = new JdbcDeleteQueryCreator(context, tree, converter, dialect, entityMetadata,
|
||||
accessor);
|
||||
return queryCreator.createQuery();
|
||||
}
|
||||
JdbcDeleteQueryCreator queryCreator = new JdbcDeleteQueryCreator(context, tree, converter, dialect, entityMetadata,
|
||||
accessor);
|
||||
return queryCreator.createQuery();
|
||||
}
|
||||
|
||||
private JdbcQueryExecution<?> getJdbcQueryExecution(@Nullable ResultSetExtractor<Boolean> extractor,
|
||||
Supplier<RowMapper<?>> rowMapper) {
|
||||
|
||||
@@ -46,9 +46,11 @@ import org.springframework.test.jdbc.JdbcTestUtils;
|
||||
* Very simple use cases for creation and usage of JdbcRepositories with test {@link Embedded} annotation in Entities.
|
||||
*
|
||||
* @author Bastian Wilhelm
|
||||
* @author Yunyoung LEE
|
||||
* @author Nikita Konev
|
||||
*/
|
||||
@IntegrationTest
|
||||
public class JdbcRepositoryEmbeddedWithCollectionIntegrationTests {
|
||||
class JdbcRepositoryEmbeddedWithCollectionIntegrationTests {
|
||||
|
||||
@Configuration
|
||||
@Import(TestConfiguration.class)
|
||||
@@ -66,7 +68,7 @@ public class JdbcRepositoryEmbeddedWithCollectionIntegrationTests {
|
||||
@Autowired Dialect dialect;
|
||||
|
||||
@Test // DATAJDBC-111
|
||||
public void savesAnEntity() throws SQLException {
|
||||
void savesAnEntity() throws SQLException {
|
||||
|
||||
DummyEntity entity = repository.save(createDummyEntity());
|
||||
|
||||
@@ -83,7 +85,7 @@ public class JdbcRepositoryEmbeddedWithCollectionIntegrationTests {
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-111
|
||||
public void saveAndLoadAnEntity() {
|
||||
void saveAndLoadAnEntity() {
|
||||
|
||||
DummyEntity entity = repository.save(createDummyEntity());
|
||||
|
||||
@@ -99,7 +101,7 @@ public class JdbcRepositoryEmbeddedWithCollectionIntegrationTests {
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-111
|
||||
public void findAllFindsAllEntities() {
|
||||
void findAllFindsAllEntities() {
|
||||
|
||||
DummyEntity entity = repository.save(createDummyEntity());
|
||||
DummyEntity other = repository.save(createDummyEntity());
|
||||
@@ -112,14 +114,14 @@ public class JdbcRepositoryEmbeddedWithCollectionIntegrationTests {
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-111
|
||||
public void findByIdReturnsEmptyWhenNoneFound() {
|
||||
void findByIdReturnsEmptyWhenNoneFound() {
|
||||
|
||||
// NOT saving anything, so DB is empty
|
||||
assertThat(repository.findById(-1L)).isEmpty();
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-111
|
||||
public void update() {
|
||||
void update() {
|
||||
|
||||
DummyEntity entity = repository.save(createDummyEntity());
|
||||
|
||||
@@ -139,7 +141,7 @@ public class JdbcRepositoryEmbeddedWithCollectionIntegrationTests {
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-111
|
||||
public void updateMany() {
|
||||
void updateMany() {
|
||||
|
||||
DummyEntity entity = repository.save(createDummyEntity());
|
||||
DummyEntity other = repository.save(createDummyEntity());
|
||||
@@ -163,7 +165,7 @@ public class JdbcRepositoryEmbeddedWithCollectionIntegrationTests {
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-111
|
||||
public void deleteById() {
|
||||
void deleteById() {
|
||||
|
||||
DummyEntity one = repository.save(createDummyEntity());
|
||||
DummyEntity two = repository.save(createDummyEntity());
|
||||
@@ -177,7 +179,7 @@ public class JdbcRepositoryEmbeddedWithCollectionIntegrationTests {
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-111
|
||||
public void deleteByEntity() {
|
||||
void deleteByEntity() {
|
||||
DummyEntity one = repository.save(createDummyEntity());
|
||||
DummyEntity two = repository.save(createDummyEntity());
|
||||
DummyEntity three = repository.save(createDummyEntity());
|
||||
@@ -190,7 +192,7 @@ public class JdbcRepositoryEmbeddedWithCollectionIntegrationTests {
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-111
|
||||
public void deleteByList() {
|
||||
void deleteByList() {
|
||||
|
||||
DummyEntity one = repository.save(createDummyEntity());
|
||||
DummyEntity two = repository.save(createDummyEntity());
|
||||
@@ -204,7 +206,7 @@ public class JdbcRepositoryEmbeddedWithCollectionIntegrationTests {
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-111
|
||||
public void deleteAll() {
|
||||
void deleteAll() {
|
||||
|
||||
repository.save(createDummyEntity());
|
||||
repository.save(createDummyEntity());
|
||||
@@ -217,52 +219,53 @@ public class JdbcRepositoryEmbeddedWithCollectionIntegrationTests {
|
||||
assertThat(repository.findAll()).isEmpty();
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-551
|
||||
public void deleteByTest() {
|
||||
@Test // GH-771
|
||||
void deleteBy() {
|
||||
|
||||
DummyEntity one = repository.save(createDummyEntity("root1"));
|
||||
DummyEntity two = repository.save(createDummyEntity("root2"));
|
||||
DummyEntity three = repository.save(createDummyEntity("root3"));
|
||||
DummyEntity one = repository.save(createDummyEntity("root1"));
|
||||
DummyEntity two = repository.save(createDummyEntity("root2"));
|
||||
DummyEntity three = repository.save(createDummyEntity("root3"));
|
||||
|
||||
assertThat(repository.deleteByTest(two.getTest())).isEqualTo(1);
|
||||
assertThat(repository.deleteByTest(two.getTest())).isEqualTo(1);
|
||||
|
||||
assertThat(repository.findAll()) //
|
||||
.extracting(DummyEntity::getId) //
|
||||
.containsExactlyInAnyOrder(one.getId(), three.getId());
|
||||
assertThat(repository.findAll()) //
|
||||
.extracting(DummyEntity::getId) //
|
||||
.containsExactlyInAnyOrder(one.getId(), three.getId());
|
||||
|
||||
Long count = template.queryForObject("select count(1) from dummy_entity2", Collections.emptyMap(), Long.class);
|
||||
assertThat(count).isEqualTo(4);
|
||||
Long count = template.queryForObject("select count(1) from dummy_entity2", Collections.emptyMap(), Long.class);
|
||||
assertThat(count).isEqualTo(4);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static DummyEntity createDummyEntity() {
|
||||
return createDummyEntity("root");
|
||||
}
|
||||
private static DummyEntity createDummyEntity() {
|
||||
return createDummyEntity("root");
|
||||
}
|
||||
|
||||
private static DummyEntity createDummyEntity(String test) {
|
||||
DummyEntity entity = new DummyEntity();
|
||||
entity.setTest(test);
|
||||
private static DummyEntity createDummyEntity(String test) {
|
||||
|
||||
final Embeddable embeddable = new Embeddable();
|
||||
embeddable.setTest("embedded");
|
||||
DummyEntity entity = new DummyEntity();
|
||||
entity.setTest(test);
|
||||
|
||||
final DummyEntity2 dummyEntity21 = new DummyEntity2();
|
||||
dummyEntity21.setTest("entity1");
|
||||
final Embeddable embeddable = new Embeddable();
|
||||
embeddable.setTest("embedded");
|
||||
|
||||
final DummyEntity2 dummyEntity22 = new DummyEntity2();
|
||||
dummyEntity22.setTest("entity2");
|
||||
final DummyEntity2 dummyEntity21 = new DummyEntity2();
|
||||
dummyEntity21.setTest("entity1");
|
||||
|
||||
embeddable.getList().add(dummyEntity21);
|
||||
embeddable.getList().add(dummyEntity22);
|
||||
final DummyEntity2 dummyEntity22 = new DummyEntity2();
|
||||
dummyEntity22.setTest("entity2");
|
||||
|
||||
entity.setEmbeddable(embeddable);
|
||||
embeddable.getList().add(dummyEntity21);
|
||||
embeddable.getList().add(dummyEntity22);
|
||||
|
||||
return entity;
|
||||
}
|
||||
entity.setEmbeddable(embeddable);
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
interface DummyEntityRepository extends CrudRepository<DummyEntity, Long> {
|
||||
int deleteByTest(String test);
|
||||
}
|
||||
int deleteByTest(String test);
|
||||
}
|
||||
|
||||
private static class DummyEntity {
|
||||
@Column("ID")
|
||||
@@ -298,8 +301,7 @@ public class JdbcRepositoryEmbeddedWithCollectionIntegrationTests {
|
||||
}
|
||||
|
||||
private static class Embeddable {
|
||||
@MappedCollection(idColumn = "DUMMY_ID", keyColumn = "ORDER_KEY")
|
||||
List<DummyEntity2> list = new ArrayList<>();
|
||||
@MappedCollection(idColumn = "DUMMY_ID", keyColumn = "ORDER_KEY") List<DummyEntity2> list = new ArrayList<>();
|
||||
|
||||
String test;
|
||||
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
package org.springframework.data.jdbc.repository;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.jupiter.api.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.repository.support.JdbcRepositoryFactory;
|
||||
import org.springframework.data.jdbc.testing.DatabaseType;
|
||||
import org.springframework.data.jdbc.testing.EnabledOnDatabase;
|
||||
import org.springframework.data.jdbc.testing.IntegrationTest;
|
||||
import org.springframework.data.jdbc.testing.TestConfiguration;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
|
||||
|
||||
/**
|
||||
* Integration tests with collections chain.
|
||||
*
|
||||
* @author Yunyoung LEE
|
||||
* @author Nikita Konev
|
||||
*/
|
||||
@IntegrationTest
|
||||
@EnabledOnDatabase(DatabaseType.HSQL)
|
||||
class JdbcRepositoryWithCollectionsChainHsqlIntegrationTests {
|
||||
|
||||
@Autowired NamedParameterJdbcTemplate template;
|
||||
@Autowired DummyEntityRepository repository;
|
||||
|
||||
private static DummyEntity createDummyEntity() {
|
||||
|
||||
DummyEntity entity = new DummyEntity();
|
||||
entity.name = "Entity Name";
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-551
|
||||
void deleteByName() {
|
||||
|
||||
ChildElement element1 = createChildElement("one");
|
||||
ChildElement element2 = createChildElement("two");
|
||||
|
||||
DummyEntity entity = createDummyEntity();
|
||||
entity.content.add(element1);
|
||||
entity.content.add(element2);
|
||||
|
||||
entity = repository.save(entity);
|
||||
|
||||
assertThat(repository.deleteByName("Entity Name")).isEqualTo(1);
|
||||
|
||||
assertThat(repository.findById(entity.id)).isEmpty();
|
||||
|
||||
Long count = template.queryForObject("select count(1) from grand_child_element", new HashMap<>(), Long.class);
|
||||
assertThat(count).isEqualTo(0);
|
||||
}
|
||||
|
||||
private ChildElement createChildElement(String name) {
|
||||
|
||||
ChildElement element = new ChildElement();
|
||||
element.name = name;
|
||||
element.content.add(createGrandChildElement(name + "1"));
|
||||
element.content.add(createGrandChildElement(name + "2"));
|
||||
return element;
|
||||
}
|
||||
|
||||
private GrandChildElement createGrandChildElement(String content) {
|
||||
|
||||
GrandChildElement element = new GrandChildElement();
|
||||
element.content = content;
|
||||
return element;
|
||||
}
|
||||
|
||||
interface DummyEntityRepository extends CrudRepository<DummyEntity, Long> {
|
||||
long deleteByName(String name);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import(TestConfiguration.class)
|
||||
static class Config {
|
||||
|
||||
@Autowired JdbcRepositoryFactory factory;
|
||||
|
||||
@Bean
|
||||
Class<?> testClass() {
|
||||
return JdbcRepositoryWithCollectionsChainHsqlIntegrationTests.class;
|
||||
}
|
||||
|
||||
@Bean
|
||||
DummyEntityRepository dummyEntityRepository() {
|
||||
return factory.getRepository(DummyEntityRepository.class);
|
||||
}
|
||||
}
|
||||
|
||||
static class DummyEntity {
|
||||
|
||||
String name;
|
||||
Set<ChildElement> content = new HashSet<>();
|
||||
@Id private Long id;
|
||||
|
||||
}
|
||||
|
||||
static class ChildElement {
|
||||
|
||||
String name;
|
||||
Set<GrandChildElement> content = new HashSet<>();
|
||||
@Id private Long id;
|
||||
}
|
||||
|
||||
static class GrandChildElement {
|
||||
|
||||
String content;
|
||||
@Id private Long id;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
package org.springframework.data.jdbc.repository;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.test.context.TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
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.repository.support.JdbcRepositoryFactory;
|
||||
import org.springframework.data.jdbc.testing.AssumeFeatureTestExecutionListener;
|
||||
import org.springframework.data.jdbc.testing.TestConfiguration;
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.TestExecutionListeners;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Integration tests with collections chain.
|
||||
*
|
||||
* @author Yunyoung LEE
|
||||
*/
|
||||
@ContextConfiguration
|
||||
@Transactional
|
||||
@TestExecutionListeners(value = AssumeFeatureTestExecutionListener.class, mergeMode = MERGE_WITH_DEFAULTS)
|
||||
@ExtendWith(SpringExtension.class)
|
||||
public class JdbcRepositoryWithCollectionsChainIntegrationTests {
|
||||
|
||||
@Autowired NamedParameterJdbcTemplate template;
|
||||
@Autowired DummyEntityRepository repository;
|
||||
|
||||
private static DummyEntity createDummyEntity() {
|
||||
|
||||
DummyEntity entity = new DummyEntity();
|
||||
entity.setName("Entity Name");
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-551
|
||||
public void deleteByName() {
|
||||
|
||||
ChildElement element1 = createChildElement("one");
|
||||
ChildElement element2 = createChildElement("two");
|
||||
|
||||
DummyEntity entity = createDummyEntity();
|
||||
entity.content.add(element1);
|
||||
entity.content.add(element2);
|
||||
|
||||
entity = repository.save(entity);
|
||||
|
||||
assertThat(repository.deleteByName("Entity Name")).isEqualTo(1);
|
||||
|
||||
assertThat(repository.findById(entity.id)).isEmpty();
|
||||
|
||||
Long count = template.queryForObject("select count(1) from grand_child_element", new HashMap<>(), Long.class);
|
||||
assertThat(count).isEqualTo(0);
|
||||
}
|
||||
|
||||
private ChildElement createChildElement(String name) {
|
||||
|
||||
ChildElement element = new ChildElement();
|
||||
element.name = name;
|
||||
element.content.add(createGrandChildElement(name + "1"));
|
||||
element.content.add(createGrandChildElement(name + "2"));
|
||||
return element;
|
||||
}
|
||||
|
||||
private GrandChildElement createGrandChildElement(String content) {
|
||||
|
||||
GrandChildElement element = new GrandChildElement();
|
||||
element.content = content;
|
||||
return element;
|
||||
}
|
||||
|
||||
interface DummyEntityRepository extends CrudRepository<DummyEntity, Long> {
|
||||
long deleteByName(String name);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import(TestConfiguration.class)
|
||||
static class Config {
|
||||
|
||||
@Autowired JdbcRepositoryFactory factory;
|
||||
|
||||
@Bean
|
||||
Class<?> testClass() {
|
||||
return JdbcRepositoryWithCollectionsChainIntegrationTests.class;
|
||||
}
|
||||
|
||||
@Bean
|
||||
DummyEntityRepository dummyEntityRepository() {
|
||||
return factory.getRepository(DummyEntityRepository.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
static class DummyEntity {
|
||||
|
||||
String name;
|
||||
Set<ChildElement> content = new HashSet<>();
|
||||
@Id private Long id;
|
||||
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
static class ChildElement {
|
||||
|
||||
String name;
|
||||
Set<GrandChildElement> content = new HashSet<>();
|
||||
@Id private Long id;
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
static class GrandChildElement {
|
||||
|
||||
String content;
|
||||
@Id private Long id;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -42,9 +42,11 @@ import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
|
||||
*
|
||||
* @author Jens Schauder
|
||||
* @author Thomas Lang
|
||||
* @author Yunyoung LEE
|
||||
* @author Nikita Konev
|
||||
*/
|
||||
@IntegrationTest
|
||||
public class JdbcRepositoryWithCollectionsIntegrationTests {
|
||||
class JdbcRepositoryWithCollectionsIntegrationTests {
|
||||
|
||||
@Autowired NamedParameterJdbcTemplate template;
|
||||
@Autowired DummyEntityRepository repository;
|
||||
@@ -57,7 +59,7 @@ public class JdbcRepositoryWithCollectionsIntegrationTests {
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-113
|
||||
public void saveAndLoadEmptySet() {
|
||||
void saveAndLoadEmptySet() {
|
||||
|
||||
DummyEntity entity = repository.save(createDummyEntity());
|
||||
|
||||
@@ -71,7 +73,7 @@ public class JdbcRepositoryWithCollectionsIntegrationTests {
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-113
|
||||
public void saveAndLoadNonEmptySet() {
|
||||
void saveAndLoadNonEmptySet() {
|
||||
|
||||
Element element1 = new Element();
|
||||
Element element2 = new Element();
|
||||
@@ -94,7 +96,7 @@ public class JdbcRepositoryWithCollectionsIntegrationTests {
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-113
|
||||
public void findAllLoadsCollection() {
|
||||
void findAllLoadsCollection() {
|
||||
|
||||
Element element1 = new Element();
|
||||
Element element2 = new Element();
|
||||
@@ -117,7 +119,7 @@ public class JdbcRepositoryWithCollectionsIntegrationTests {
|
||||
|
||||
@Test // DATAJDBC-113
|
||||
@EnabledOnFeature(SUPPORTS_GENERATED_IDS_IN_REFERENCED_ENTITIES)
|
||||
public void updateSet() {
|
||||
void updateSet() {
|
||||
|
||||
Element element1 = createElement("one");
|
||||
Element element2 = createElement("two");
|
||||
@@ -154,7 +156,7 @@ public class JdbcRepositoryWithCollectionsIntegrationTests {
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-113
|
||||
public void deletingWithSet() {
|
||||
void deletingWithSet() {
|
||||
|
||||
Element element1 = createElement("one");
|
||||
Element element2 = createElement("two");
|
||||
@@ -173,8 +175,8 @@ public class JdbcRepositoryWithCollectionsIntegrationTests {
|
||||
assertThat(count).isEqualTo(0);
|
||||
}
|
||||
|
||||
@Test // DATAJDBC-551
|
||||
public void deleteByName() {
|
||||
@Test // GH-771
|
||||
void deleteByName() {
|
||||
|
||||
Element element1 = createElement("one");
|
||||
Element element2 = createElement("two");
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
CREATE TABLE DUMMY_ENTITY
|
||||
(
|
||||
ID BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY,
|
||||
NAME VARCHAR(100)
|
||||
);
|
||||
CREATE TABLE CHILD_ELEMENT
|
||||
(
|
||||
ID BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH 1) PRIMARY KEY,
|
||||
NAME VARCHAR(100),
|
||||
DUMMY_ENTITY BIGINT
|
||||
);
|
||||
CREATE TABLE GRAND_CHILD_ELEMENT
|
||||
(
|
||||
ID BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH 1) PRIMARY KEY,
|
||||
CONTENT VARCHAR(100),
|
||||
CHILD_ELEMENT BIGINT
|
||||
);
|
||||
@@ -1,3 +0,0 @@
|
||||
CREATE TABLE dummy_entity ( id BIGINT GENERATED BY DEFAULT AS IDENTITY ( START WITH 1 ) PRIMARY KEY, NAME VARCHAR(100));
|
||||
CREATE TABLE child_element (id BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH 1) PRIMARY KEY, NAME VARCHAR(100), dummy_entity BIGINT);
|
||||
CREATE TABLE grand_child_element (id BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH 1) PRIMARY KEY, CONTENT VARCHAR(100), child_element BIGINT);
|
||||
Reference in New Issue
Block a user