Browse Source

DATAJDBC-112 - Processing feedback from review.

Code formatting. Removed few superfluous lines of code.

Renamed JdbcInterpreter to DefaultJdbcInterpreter.
The prefix Jdbc doesn't really carry much information in the SD JDBC project.

Renamed jdbcConverter fields to jdbcEntityWriter in order to match the type names.

Renamed DbChange to AggregateChange.
It isn't really about the database but about the aggregate.
pull/9/merge
Jens Schauder 9 years ago committed by Greg Turnquist
parent
commit
c55dd9e177
No known key found for this signature in database
GPG Key ID: CB2FA4D512B5C413
  1. 5
      src/main/java/org/springframework/data/jdbc/core/DefaultJdbcInterpreter.java
  2. 11
      src/main/java/org/springframework/data/jdbc/core/EntityRowMapper.java
  3. 8
      src/main/java/org/springframework/data/jdbc/core/JdbcEntityOperations.java
  4. 66
      src/main/java/org/springframework/data/jdbc/core/JdbcEntityTemplate.java
  5. 25
      src/main/java/org/springframework/data/jdbc/core/SelectBuilder.java
  6. 5
      src/main/java/org/springframework/data/jdbc/core/SqlGenerator.java
  7. 4
      src/main/java/org/springframework/data/jdbc/core/conversion/AggregateChange.java
  8. 6
      src/main/java/org/springframework/data/jdbc/core/conversion/Interpreter.java
  9. 22
      src/main/java/org/springframework/data/jdbc/core/conversion/JdbcEntityDeleteWriter.java
  10. 39
      src/main/java/org/springframework/data/jdbc/core/conversion/JdbcEntityWriter.java
  11. 14
      src/main/java/org/springframework/data/jdbc/core/conversion/JdbcEntityWriterSupport.java
  12. 4
      src/main/java/org/springframework/data/jdbc/mapping/model/PropertyPaths.java
  13. 2
      src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactory.java
  14. 39
      src/test/java/org/springframework/data/jdbc/core/JdbcEntityTemplateIntegrationTests.java
  15. 8
      src/test/java/org/springframework/data/jdbc/core/conversion/JdbcEntityDeleteWriterUnitTests.java
  16. 20
      src/test/java/org/springframework/data/jdbc/core/conversion/JdbcEntityWriterUnitTests.java

5
src/main/java/org/springframework/data/jdbc/core/JdbcInterpreter.java → src/main/java/org/springframework/data/jdbc/core/DefaultJdbcInterpreter.java

@ -35,12 +35,13 @@ import org.springframework.data.jdbc.mapping.model.JdbcPersistentEntity;
* *
* @author Jens Schauder * @author Jens Schauder
*/ */
class JdbcInterpreter implements Interpreter { class DefaultJdbcInterpreter implements Interpreter {
private final JdbcMappingContext context; private final JdbcMappingContext context;
private final JdbcEntityTemplate template; private final JdbcEntityTemplate template;
JdbcInterpreter(JdbcMappingContext context, JdbcEntityTemplate template) { DefaultJdbcInterpreter(JdbcMappingContext context, JdbcEntityTemplate template) {
this.context = context; this.context = context;
this.template = template; this.template = template;
} }

11
src/main/java/org/springframework/data/jdbc/core/EntityRowMapper.java

@ -75,8 +75,11 @@ class EntityRowMapper<T> implements RowMapper<T> {
private Object readFrom(ResultSet resultSet, JdbcPersistentProperty property, String prefix) { private Object readFrom(ResultSet resultSet, JdbcPersistentProperty property, String prefix) {
try { try {
if (property.isEntity())
if (property.isEntity()) {
return readEntityFrom(resultSet, property); return readEntityFrom(resultSet, property);
}
return resultSet.getObject(prefix + property.getColumnName()); return resultSet.getObject(prefix + property.getColumnName());
} catch (SQLException o_O) { } catch (SQLException o_O) {
throw new MappingException(String.format("Could not read property %s from result set!", property), o_O); throw new MappingException(String.format("Could not read property %s from result set!", property), o_O);
@ -90,8 +93,9 @@ class EntityRowMapper<T> implements RowMapper<T> {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
JdbcPersistentEntity<S> entity = (JdbcPersistentEntity<S>) context.getRequiredPersistentEntity(property.getType()); JdbcPersistentEntity<S> entity = (JdbcPersistentEntity<S>) context.getRequiredPersistentEntity(property.getType());
if (readFrom(rs, entity.getRequiredIdProperty(), prefix) == null) if (readFrom(rs, entity.getRequiredIdProperty(), prefix) == null) {
return null; return null;
}
S instance = instantiator.createInstance(entity, ResultSetParameterValueProvider.of(rs, conversions, prefix)); S instance = instantiator.createInstance(entity, ResultSetParameterValueProvider.of(rs, conversions, prefix));
@ -120,8 +124,9 @@ class EntityRowMapper<T> implements RowMapper<T> {
public <T> T getParameterValue(Parameter<T, JdbcPersistentProperty> parameter) { public <T> T getParameterValue(Parameter<T, JdbcPersistentProperty> parameter) {
String name = parameter.getName(); String name = parameter.getName();
if (name == null) if (name == null) {
return null; return null;
}
try { try {
return conversionService.convert(resultSet.getObject(prefix + name), parameter.getType().getType()); return conversionService.convert(resultSet.getObject(prefix + name), parameter.getType().getType());

8
src/main/java/org/springframework/data/jdbc/core/JdbcEntityOperations.java

@ -24,6 +24,8 @@ import java.util.Map;
*/ */
public interface JdbcEntityOperations { public interface JdbcEntityOperations {
<T> void save(T instance, Class<T> domainType);
<T> void insert(T instance, Class<T> domainType, Map<String, Object> additionalParameter); <T> void insert(T instance, Class<T> domainType, Map<String, Object> additionalParameter);
<T> void update(T instance, Class<T> domainType); <T> void update(T instance, Class<T> domainType);
@ -32,6 +34,8 @@ public interface JdbcEntityOperations {
<T> void delete(T entity, Class<T> domainType); <T> void delete(T entity, Class<T> domainType);
void deleteAll(Class<?> domainType);
long count(Class<?> domainType); long count(Class<?> domainType);
<T> T findById(Object id, Class<T> domainType); <T> T findById(Object id, Class<T> domainType);
@ -41,8 +45,4 @@ public interface JdbcEntityOperations {
<T> Iterable<T> findAll(Class<T> domainType); <T> Iterable<T> findAll(Class<T> domainType);
<T> boolean existsById(Object id, Class<T> domainType); <T> boolean existsById(Object id, Class<T> domainType);
void deleteAll(Class<?> domainType);
<T> void save(T instance, Class<T> domainType);
} }

66
src/main/java/org/springframework/data/jdbc/core/JdbcEntityTemplate.java

@ -28,11 +28,11 @@ import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.dao.NonTransientDataAccessException; import org.springframework.dao.NonTransientDataAccessException;
import org.springframework.data.convert.Jsr310Converters; import org.springframework.data.convert.Jsr310Converters;
import org.springframework.data.jdbc.core.conversion.DbChange; import org.springframework.data.jdbc.core.conversion.AggregateChange;
import org.springframework.data.jdbc.core.conversion.DbChange.Kind; import org.springframework.data.jdbc.core.conversion.AggregateChange.Kind;
import org.springframework.data.jdbc.core.conversion.Interpreter; import org.springframework.data.jdbc.core.conversion.Interpreter;
import org.springframework.data.jdbc.core.conversion.JdbcEntityWriter;
import org.springframework.data.jdbc.core.conversion.JdbcEntityDeleteWriter; import org.springframework.data.jdbc.core.conversion.JdbcEntityDeleteWriter;
import org.springframework.data.jdbc.core.conversion.JdbcEntityWriter;
import org.springframework.data.jdbc.mapping.event.AfterDelete; import org.springframework.data.jdbc.mapping.event.AfterDelete;
import org.springframework.data.jdbc.mapping.event.AfterInsert; import org.springframework.data.jdbc.mapping.event.AfterInsert;
import org.springframework.data.jdbc.mapping.event.AfterUpdate; import org.springframework.data.jdbc.mapping.event.AfterUpdate;
@ -63,7 +63,7 @@ import org.springframework.util.Assert;
public class JdbcEntityTemplate implements JdbcEntityOperations { public class JdbcEntityTemplate implements JdbcEntityOperations {
private static final String ENTITY_NEW_AFTER_INSERT = "Entity [%s] still 'new' after insert. Please set either" private static final String ENTITY_NEW_AFTER_INSERT = "Entity [%s] still 'new' after insert. Please set either"
+ " the id property in a before insert event handler, or ensure the database creates a value and your " + " the id property in a BeforeInsert event handler, or ensure the database creates a value and your "
+ "JDBC driver returns it."; + "JDBC driver returns it.";
private final ApplicationEventPublisher publisher; private final ApplicationEventPublisher publisher;
@ -73,8 +73,8 @@ public class JdbcEntityTemplate implements JdbcEntityOperations {
private final Interpreter interpreter; private final Interpreter interpreter;
private final SqlGeneratorSource sqlGeneratorSource; private final SqlGeneratorSource sqlGeneratorSource;
private final JdbcEntityWriter jdbcConverter; private final JdbcEntityWriter jdbcEntityWriter;
private final JdbcEntityDeleteWriter jdbcEntityDeleteConverter; private final JdbcEntityDeleteWriter jdbcEntityDeleteWriter;
public JdbcEntityTemplate(ApplicationEventPublisher publisher, NamedParameterJdbcOperations operations, public JdbcEntityTemplate(ApplicationEventPublisher publisher, NamedParameterJdbcOperations operations,
JdbcMappingContext context) { JdbcMappingContext context) {
@ -83,10 +83,10 @@ public class JdbcEntityTemplate implements JdbcEntityOperations {
this.operations = operations; this.operations = operations;
this.context = context; this.context = context;
jdbcConverter = new JdbcEntityWriter(this.context); this.jdbcEntityWriter = new JdbcEntityWriter(this.context);
jdbcEntityDeleteConverter = new JdbcEntityDeleteWriter(this.context); this.jdbcEntityDeleteWriter = new JdbcEntityDeleteWriter(this.context);
sqlGeneratorSource = new SqlGeneratorSource(this.context); this.sqlGeneratorSource = new SqlGeneratorSource(this.context);
interpreter = new JdbcInterpreter(this.context, this); this.interpreter = new DefaultJdbcInterpreter(this.context, this);
} }
private static GenericConversionService getDefaultConversionService() { private static GenericConversionService getDefaultConversionService() {
@ -99,11 +99,11 @@ public class JdbcEntityTemplate implements JdbcEntityOperations {
@Override @Override
public <T> void save(T instance, Class<T> domainType) { public <T> void save(T instance, Class<T> domainType) {
createDbChange(instance).executeWith(interpreter); createChange(instance).executeWith(interpreter);
} }
@Override @Override
public <T> void insert(T instance, Class<T> domainType, Map<String, Object> additionalParameter) { public <T> void insert(T instance, Class<T> domainType, Map<String, Object> additionalParameters) {
publisher.publishEvent(new BeforeInsert(instance)); publisher.publishEvent(new BeforeInsert(instance));
@ -118,9 +118,9 @@ public class JdbcEntityTemplate implements JdbcEntityOperations {
JdbcPersistentProperty idProperty = persistentEntity.getRequiredIdProperty(); JdbcPersistentProperty idProperty = persistentEntity.getRequiredIdProperty();
propertyMap.put(idProperty.getColumnName(), convert(idValue, idProperty.getColumnType())); propertyMap.put(idProperty.getColumnName(), convert(idValue, idProperty.getColumnType()));
propertyMap.putAll(additionalParameter); propertyMap.putAll(additionalParameters);
operations.update(sql(domainType).getInsert(idValue == null, additionalParameter.keySet()), operations.update(sql(domainType).getInsert(idValue == null, additionalParameters.keySet()),
new MapSqlParameterSource(propertyMap), holder); new MapSqlParameterSource(propertyMap), holder);
setIdFromJdbc(instance, holder, persistentEntity); setIdFromJdbc(instance, holder, persistentEntity);
@ -177,8 +177,13 @@ public class JdbcEntityTemplate implements JdbcEntityOperations {
String findAllInListSql = sql(domainType).getFindAllInList(); String findAllInListSql = sql(domainType).getFindAllInList();
Class<?> targetType = getRequiredPersistentEntity(domainType).getRequiredIdProperty().getColumnType(); Class<?> targetType = getRequiredPersistentEntity(domainType).getRequiredIdProperty().getColumnType();
MapSqlParameterSource parameter = new MapSqlParameterSource("ids",
StreamSupport.stream(ids.spliterator(), false).map(id -> convert(id, targetType)).collect(Collectors.toList())); MapSqlParameterSource parameter = new MapSqlParameterSource( //
"ids", //
StreamSupport.stream(ids.spliterator(), false) //
.map(id -> convert(id, targetType)) //
.collect(Collectors.toList()) //
);
return operations.query(findAllInListSql, parameter, getEntityRowMapper(domainType)); return operations.query(findAllInListSql, parameter, getEntityRowMapper(domainType));
} }
@ -199,7 +204,7 @@ public class JdbcEntityTemplate implements JdbcEntityOperations {
@Override @Override
public void deleteAll(Class<?> domainType) { public void deleteAll(Class<?> domainType) {
DbChange change = createDeletingDbChange(domainType); AggregateChange change = createDeletingChange(domainType);
change.executeWith(interpreter); change.executeWith(interpreter);
} }
@ -225,7 +230,6 @@ public class JdbcEntityTemplate implements JdbcEntityOperations {
publisher.publishEvent(new BeforeDelete(specifiedId, optionalEntity)); publisher.publishEvent(new BeforeDelete(specifiedId, optionalEntity));
String deleteByIdSql = sql(domainType).getDeleteById(); String deleteByIdSql = sql(domainType).getDeleteById();
MapSqlParameterSource parameter = createIdParameterSource(specifiedId.getValue(), domainType); MapSqlParameterSource parameter = createIdParameterSource(specifiedId.getValue(), domainType);
operations.update(deleteByIdSql, parameter); operations.update(deleteByIdSql, parameter);
@ -235,30 +239,30 @@ public class JdbcEntityTemplate implements JdbcEntityOperations {
private void deleteTree(Object id, Object entity, Class<?> domainType) { private void deleteTree(Object id, Object entity, Class<?> domainType) {
DbChange change = createDeletingDbChange(id, entity, domainType); AggregateChange change = createDeletingChange(id, entity, domainType);
change.executeWith(interpreter); change.executeWith(interpreter);
} }
private <T> DbChange createDbChange(T instance) { private <T> AggregateChange createChange(T instance) {
DbChange dbChange = new DbChange(Kind.SAVE, instance.getClass(), instance); AggregateChange aggregateChange = new AggregateChange(Kind.SAVE, instance.getClass(), instance);
jdbcConverter.write(instance, dbChange); jdbcEntityWriter.write(instance, aggregateChange);
return dbChange; return aggregateChange;
} }
private DbChange createDeletingDbChange(Object id, Object entity, Class<?> domainType) { private AggregateChange createDeletingChange(Object id, Object entity, Class<?> domainType) {
DbChange dbChange = new DbChange(Kind.DELETE, domainType, entity); AggregateChange aggregateChange = new AggregateChange(Kind.DELETE, domainType, entity);
jdbcEntityDeleteConverter.write(id, dbChange); jdbcEntityDeleteWriter.write(id, aggregateChange);
return dbChange; return aggregateChange;
} }
private DbChange createDeletingDbChange(Class<?> domainType) { private AggregateChange createDeletingChange(Class<?> domainType) {
DbChange dbChange = new DbChange(Kind.DELETE, domainType, null); AggregateChange aggregateChange = new AggregateChange(Kind.DELETE, domainType, null);
jdbcEntityDeleteConverter.write(null, dbChange); jdbcEntityDeleteWriter.write(null, aggregateChange);
return dbChange; return aggregateChange;
} }
private <T> MapSqlParameterSource createIdParameterSource(Object id, Class<T> domainType) { private <T> MapSqlParameterSource createIdParameterSource(Object id, Class<T> domainType) {

25
src/main/java/org/springframework/data/jdbc/core/SelectBuilder.java

@ -47,11 +47,13 @@ class SelectBuilder {
} }
SelectBuilder where(Function<WhereConditionBuilder, WhereConditionBuilder> whereSpec) { SelectBuilder where(Function<WhereConditionBuilder, WhereConditionBuilder> whereSpec) {
conditions.add(whereSpec.apply(new WhereConditionBuilder(this)).build()); conditions.add(whereSpec.apply(new WhereConditionBuilder(this)).build());
return this; return this;
} }
SelectBuilder join(Function<Join.JoinBuilder, Join.JoinBuilder> joinSpec) { SelectBuilder join(Function<Join.JoinBuilder, Join.JoinBuilder> joinSpec) {
joins.add(joinSpec.apply(Join.builder()).build()); joins.add(joinSpec.apply(Join.builder()).build());
return this; return this;
} }
@ -62,9 +64,15 @@ class SelectBuilder {
} }
private String whereClause() { private String whereClause() {
if (conditions.isEmpty())
if (conditions.isEmpty()) {
return ""; return "";
return conditions.stream().map(wc -> wc.toSql()).collect(Collectors.joining("AND", " WHERE ", "")); }
return conditions.stream() //
.map(WhereCondition::toSql) //
.collect(Collectors.joining("AND", " WHERE ", "") //
);
} }
private String joinClause() { private String joinClause() {
@ -76,13 +84,16 @@ class SelectBuilder {
} }
private String joinConditions(Join j) { private String joinConditions(Join j) {
return j.conditions.stream().map(w -> String.format("%s %s %s", w.fromExpression, w.operation, w.toExpression))
return j.conditions.stream() //
.map(w -> String.format("%s %s %s", w.fromExpression, w.operation, w.toExpression)) //
.collect(Collectors.joining(" AND ", " ON ", "")); .collect(Collectors.joining(" AND ", " ON ", ""));
} }
private String selectFrom() { private String selectFrom() {
return columns.stream() // return columns.stream() //
.map(c -> c.columnDefinition()) // .map(Column::columnDefinition) //
.collect(Collectors.joining(", ", "SELECT ", " FROM " + tableName)); .collect(Collectors.joining(", ", "SELECT ", " FROM " + tableName));
} }
@ -101,13 +112,13 @@ class SelectBuilder {
WhereConditionBuilder eq() { WhereConditionBuilder eq() {
operation = "="; this.operation = "=";
return this; return this;
} }
public WhereConditionBuilder in() { public WhereConditionBuilder in() {
operation = "in"; this.operation = "in";
return this; return this;
} }
@ -125,7 +136,7 @@ class SelectBuilder {
WhereConditionBuilder variable(String var) { WhereConditionBuilder variable(String var) {
expression = ":" + var; this.expression = ":" + var;
return this; return this;
} }

5
src/main/java/org/springframework/data/jdbc/core/SqlGenerator.java

@ -158,7 +158,9 @@ class SqlGenerator {
} }
private Stream<String> getColumnNameStream(String prefix) { private Stream<String> getColumnNameStream(String prefix) {
return StreamUtils.createStreamFromIterator(entity.iterator()).flatMap(p -> getColumnNameStream(p, prefix));
return StreamUtils.createStreamFromIterator(entity.iterator()) //
.flatMap(p -> getColumnNameStream(p, prefix));
} }
private Stream<String> getColumnNameStream(JdbcPersistentProperty p, String prefix) { private Stream<String> getColumnNameStream(JdbcPersistentProperty p, String prefix) {
@ -216,6 +218,7 @@ class SqlGenerator {
} }
String createDeleteAllSql(PropertyPath path) { String createDeleteAllSql(PropertyPath path) {
if (path == null) { if (path == null) {
return String.format("DELETE FROM %s", entity.getTableName()); return String.format("DELETE FROM %s", entity.getTableName());
} }

4
src/main/java/org/springframework/data/jdbc/core/conversion/DbChange.java → src/main/java/org/springframework/data/jdbc/core/conversion/AggregateChange.java

@ -22,11 +22,13 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
* Represents the change happening to the aggregate (as used in the context of Domain Driven Design) as a whole.
*
* @author Jens Schauder * @author Jens Schauder
*/ */
@RequiredArgsConstructor @RequiredArgsConstructor
@Getter @Getter
public class DbChange<T> { public class AggregateChange<T> {
private final Kind kind; private final Kind kind;

6
src/main/java/org/springframework/data/jdbc/core/conversion/Interpreter.java

@ -25,9 +25,11 @@ import org.springframework.data.jdbc.core.conversion.DbAction.Update;
*/ */
public interface Interpreter { public interface Interpreter {
<T>void interpret(Update<T> update); <T> void interpret(Update<T> update);
<T>void interpret(Insert<T> insert);
<T> void interpret(Insert<T> insert);
<T> void interpret(Delete<T> delete); <T> void interpret(Delete<T> delete);
<T> void interpret(DeleteAll<T> delete); <T> void interpret(DeleteAll<T> delete);
} }

22
src/main/java/org/springframework/data/jdbc/core/conversion/JdbcEntityDeleteWriter.java

@ -19,7 +19,7 @@ import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
import org.springframework.data.jdbc.mapping.model.PropertyPaths; import org.springframework.data.jdbc.mapping.model.PropertyPaths;
/** /**
* Converts an entity that is about to be deleted into {@link DbAction}s inside a {@link DbChange} that need to be * Converts an entity that is about to be deleted into {@link DbAction}s inside a {@link AggregateChange} that need to be
* executed against the database to recreate the appropriate state in the database. * executed against the database to recreate the appropriate state in the database.
* *
* @author Jens Schauder * @author Jens Schauder
@ -31,28 +31,28 @@ public class JdbcEntityDeleteWriter extends JdbcEntityWriterSupport {
} }
@Override @Override
public void write(Object id, DbChange dbChange) { public void write(Object id, AggregateChange aggregateChange) {
if (id == null) { if (id == null) {
deleteAll(dbChange); deleteAll(aggregateChange);
} else { } else {
deleteById(id, dbChange); deleteById(id, aggregateChange);
} }
} }
private void deleteAll(DbChange dbChange) { private void deleteAll(AggregateChange aggregateChange) {
context.referencedEntities(dbChange.getEntityType(), null) context.referencedEntities(aggregateChange.getEntityType(), null)
.forEach(p -> dbChange.addAction(DbAction.deleteAll(PropertyPaths.getLeafType(p), p, null))); .forEach(p -> aggregateChange.addAction(DbAction.deleteAll(PropertyPaths.getLeafType(p), p, null)));
dbChange.addAction(DbAction.deleteAll(dbChange.getEntityType(), null, null)); aggregateChange.addAction(DbAction.deleteAll(aggregateChange.getEntityType(), null, null));
} }
private void deleteById(Object id, DbChange dbChange) { private void deleteById(Object id, AggregateChange aggregateChange) {
deleteReferencedEntities(id, dbChange); deleteReferencedEntities(id, aggregateChange);
dbChange.addAction(DbAction.delete(id, dbChange.getEntityType(), dbChange.getEntity(), null, null)); aggregateChange.addAction(DbAction.delete(id, aggregateChange.getEntityType(), aggregateChange.getEntity(), null, null));
} }
} }

39
src/main/java/org/springframework/data/jdbc/core/conversion/JdbcEntityWriter.java

@ -28,7 +28,7 @@ import org.springframework.data.mapping.PersistentPropertyAccessor;
import org.springframework.data.util.StreamUtils; import org.springframework.data.util.StreamUtils;
/** /**
* Converts an entity that is about to be saved into {@link DbAction}s inside a {@link DbChange} that need to be * Converts an entity that is about to be saved into {@link DbAction}s inside a {@link AggregateChange} that need to be
* executed against the database to recreate the appropriate state in the database. * executed against the database to recreate the appropriate state in the database.
* *
* @author Jens Schauder * @author Jens Schauder
@ -40,39 +40,40 @@ public class JdbcEntityWriter extends JdbcEntityWriterSupport {
} }
@Override @Override
public void write(Object o, DbChange dbChange) { public void write(Object o, AggregateChange aggregateChange) {
write(o, dbChange, null); write(o, aggregateChange, null);
} }
private void write(Object o, DbChange dbChange, DbAction dependingOn) { private void write(Object o, AggregateChange aggregateChange, DbAction dependingOn) {
JdbcPersistentEntity<?> persistentEntity = context.getRequiredPersistentEntity(dbChange.getEntityType()); JdbcPersistentEntity<?> persistentEntity = context.getRequiredPersistentEntity(aggregateChange.getEntityType());
JdbcPersistentEntityInformation<Object, ?> entityInformation = context JdbcPersistentEntityInformation<Object, ?> entityInformation = context
.getRequiredPersistentEntityInformation((Class<Object>) o.getClass()); .getRequiredPersistentEntityInformation((Class<Object>) o.getClass());
if (entityInformation.isNew(o)) { if (entityInformation.isNew(o)) {
Insert<Object> insert = DbAction.insert(o, dependingOn); Insert<Object> insert = DbAction.insert(o, dependingOn);
dbChange.addAction(insert); aggregateChange.addAction(insert);
referencedEntities(o).forEach(e -> saveReferencedEntities(e, dbChange, insert)); referencedEntities(o).forEach(e -> saveReferencedEntities(e, aggregateChange, insert));
} else { } else {
deleteReferencedEntities(entityInformation.getRequiredId(o), dbChange); deleteReferencedEntities(entityInformation.getRequiredId(o), aggregateChange);
Update<Object> update = DbAction.update(o, dependingOn); Update<Object> update = DbAction.update(o, dependingOn);
dbChange.addAction(update); aggregateChange.addAction(update);
referencedEntities(o).forEach(e -> insertReferencedEntities(e, dbChange, update)); referencedEntities(o).forEach(e -> insertReferencedEntities(e, aggregateChange, update));
} }
} }
private void saveReferencedEntities(Object o, DbChange dbChange, DbAction dependingOn) { private void saveReferencedEntities(Object o, AggregateChange aggregateChange, DbAction dependingOn) {
DbAction action = saveAction(o, dependingOn); DbAction action = saveAction(o, dependingOn);
dbChange.addAction(action); aggregateChange.addAction(action);
referencedEntities(o).forEach(e -> saveReferencedEntities(e, dbChange, action)); referencedEntities(o).forEach(e -> saveReferencedEntities(e, aggregateChange, action));
} }
private <T> DbAction saveAction(T t, DbAction dependingOn) { private <T> DbAction saveAction(T t, DbAction dependingOn) {
@ -80,17 +81,17 @@ public class JdbcEntityWriter extends JdbcEntityWriterSupport {
JdbcPersistentEntityInformation<T, ?> entityInformation = context JdbcPersistentEntityInformation<T, ?> entityInformation = context
.getRequiredPersistentEntityInformation((Class<T>) t.getClass()); .getRequiredPersistentEntityInformation((Class<T>) t.getClass());
if (entityInformation.isNew(t)) if (entityInformation.isNew(t)) {
return DbAction.insert(t, dependingOn); return DbAction.insert(t, dependingOn);
else } else {
return DbAction.update(t, dependingOn); return DbAction.update(t, dependingOn);
}
} }
private void insertReferencedEntities(Object o, DbChange dbChange, DbAction dependingOn) { private void insertReferencedEntities(Object o, AggregateChange aggregateChange, DbAction dependingOn) {
System.out.println("adding an insert"); aggregateChange.addAction(DbAction.insert(o, dependingOn));
dbChange.addAction(DbAction.insert(o, dependingOn)); referencedEntities(o).forEach(e -> insertReferencedEntities(e, aggregateChange, dependingOn));
referencedEntities(o).forEach(e -> insertReferencedEntities(e, dbChange, dependingOn));
} }
private Stream<Object> referencedEntities(Object o) { private Stream<Object> referencedEntities(Object o) {

14
src/main/java/org/springframework/data/jdbc/core/conversion/JdbcEntityWriterSupport.java

@ -20,11 +20,11 @@ import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
import org.springframework.data.jdbc.mapping.model.PropertyPaths; import org.springframework.data.jdbc.mapping.model.PropertyPaths;
/** /**
* Common infrastructure needed by different implementations of {@link EntityWriter}<Object, DbChange>. * Common infrastructure needed by different implementations of {@link EntityWriter}<Object, AggregateChange>.
* *
* @author Jens Schauder * @author Jens Schauder
*/ */
abstract class JdbcEntityWriterSupport implements EntityWriter<Object, DbChange> { abstract class JdbcEntityWriterSupport implements EntityWriter<Object, AggregateChange> {
protected final JdbcMappingContext context; protected final JdbcMappingContext context;
JdbcEntityWriterSupport(JdbcMappingContext context) { JdbcEntityWriterSupport(JdbcMappingContext context) {
@ -32,15 +32,15 @@ abstract class JdbcEntityWriterSupport implements EntityWriter<Object, DbChange>
} }
/** /**
* add {@link org.springframework.data.jdbc.core.conversion.DbAction.Delete} actions to the {@link DbChange} for * add {@link org.springframework.data.jdbc.core.conversion.DbAction.Delete} actions to the {@link AggregateChange} for
* deleting all referenced entities. * deleting all referenced entities.
* *
* @param id id of the aggregate root, of which the referenced entities get deleted. * @param id id of the aggregate root, of which the referenced entities get deleted.
* @param dbChange the change object to which the actions should get added. Must not be {@literal null} * @param aggregateChange the change object to which the actions should get added. Must not be {@literal null}
*/ */
void deleteReferencedEntities(Object id, DbChange dbChange) { void deleteReferencedEntities(Object id, AggregateChange aggregateChange) {
context.referencedEntities(dbChange.getEntityType(), null) context.referencedEntities(aggregateChange.getEntityType(), null)
.forEach(p -> dbChange.addAction(DbAction.delete(id, PropertyPaths.getLeafType(p), null, p, null))); .forEach(p -> aggregateChange.addAction(DbAction.delete(id, PropertyPaths.getLeafType(p), null, p, null)));
} }
} }

4
src/main/java/org/springframework/data/jdbc/mapping/model/PropertyPaths.java

@ -29,8 +29,10 @@ import org.springframework.util.Assert;
public class PropertyPaths { public class PropertyPaths {
public static Class<?> getLeafType(PropertyPath path) { public static Class<?> getLeafType(PropertyPath path) {
if (path.hasNext())
if (path.hasNext()) {
return getLeafType(path.next()); return getLeafType(path.next());
}
return path.getType(); return path.getType();
} }

2
src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactory.java

@ -46,8 +46,6 @@ public class JdbcRepositoryFactory extends RepositoryFactorySupport {
public <T, ID> EntityInformation<T, ID> getEntityInformation(Class<T> aClass) { public <T, ID> EntityInformation<T, ID> getEntityInformation(Class<T> aClass) {
JdbcPersistentEntity<?> persistentEntity = context.getRequiredPersistentEntity(aClass); JdbcPersistentEntity<?> persistentEntity = context.getRequiredPersistentEntity(aClass);
if (persistentEntity == null)
return null;
return new BasicJdbcPersistentEntityInformation<>((JdbcPersistentEntity<T>) persistentEntity); return new BasicJdbcPersistentEntityInformation<>((JdbcPersistentEntity<T>) persistentEntity);
} }

39
src/test/java/org/springframework/data/jdbc/core/JdbcEntityTemplateIntegrationTests.java

@ -47,26 +47,8 @@ import org.springframework.transaction.annotation.Transactional;
@Transactional @Transactional
public class JdbcEntityTemplateIntegrationTests { public class JdbcEntityTemplateIntegrationTests {
@Configuration
@Import(TestConfiguration.class)
static class Config {
@Bean
Class<?> testClass() {
return JdbcEntityTemplateIntegrationTests.class;
}
@Bean
JdbcEntityOperations operations(ApplicationEventPublisher publisher,
NamedParameterJdbcOperations namedParameterJdbcOperations) {
return new JdbcEntityTemplate(publisher, namedParameterJdbcOperations, new JdbcMappingContext());
}
}
@ClassRule public static final SpringClassRule classRule = new SpringClassRule(); @ClassRule public static final SpringClassRule classRule = new SpringClassRule();
@Rule public SpringMethodRule methodRule = new SpringMethodRule(); @Rule public SpringMethodRule methodRule = new SpringMethodRule();
@Autowired JdbcEntityOperations template; @Autowired JdbcEntityOperations template;
LegoSet legoSet = createLegoSet(); LegoSet legoSet = createLegoSet();
@ -247,12 +229,31 @@ public class JdbcEntityTemplateIntegrationTests {
private String name; private String name;
private Manual manual; private Manual manual;
} }
@Data @Data
static class Manual { static class Manual {
@Id private final Long id;
@Id private final Long id;
private String content; private String content;
}
@Configuration
@Import(TestConfiguration.class)
static class Config {
@Bean
Class<?> testClass() {
return JdbcEntityTemplateIntegrationTests.class;
}
@Bean
JdbcEntityOperations operations(ApplicationEventPublisher publisher,
NamedParameterJdbcOperations namedParameterJdbcOperations) {
return new JdbcEntityTemplate(publisher, namedParameterJdbcOperations, new JdbcMappingContext());
}
} }
} }

8
src/test/java/org/springframework/data/jdbc/core/conversion/JdbcEntityDeleteWriterUnitTests.java

@ -23,8 +23,8 @@ import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.data.annotation.Id; import org.springframework.data.annotation.Id;
import org.springframework.data.jdbc.core.conversion.AggregateChange.Kind;
import org.springframework.data.jdbc.core.conversion.DbAction.Delete; import org.springframework.data.jdbc.core.conversion.DbAction.Delete;
import org.springframework.data.jdbc.core.conversion.DbChange.Kind;
import org.springframework.data.jdbc.mapping.model.JdbcMappingContext; import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
/** /**
@ -42,11 +42,11 @@ public class JdbcEntityDeleteWriterUnitTests {
SomeEntity entity = new SomeEntity(23L); SomeEntity entity = new SomeEntity(23L);
DbChange<SomeEntity> dbChange = new DbChange(Kind.DELETE, SomeEntity.class, entity); AggregateChange<SomeEntity> aggregateChange = new AggregateChange(Kind.DELETE, SomeEntity.class, entity);
converter.write(entity, dbChange); converter.write(entity, aggregateChange);
Assertions.assertThat(dbChange.getActions()).extracting(DbAction::getClass, DbAction::getEntityType) Assertions.assertThat(aggregateChange.getActions()).extracting(DbAction::getClass, DbAction::getEntityType)
.containsExactly( // .containsExactly( //
Tuple.tuple(Delete.class, YetAnother.class), // Tuple.tuple(Delete.class, YetAnother.class), //
Tuple.tuple(Delete.class, OtherEntity.class), // Tuple.tuple(Delete.class, OtherEntity.class), //

20
src/test/java/org/springframework/data/jdbc/core/conversion/JdbcEntityWriterUnitTests.java

@ -23,10 +23,10 @@ import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner; import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.data.annotation.Id; import org.springframework.data.annotation.Id;
import org.springframework.data.jdbc.core.conversion.AggregateChange.Kind;
import org.springframework.data.jdbc.core.conversion.DbAction.Delete; import org.springframework.data.jdbc.core.conversion.DbAction.Delete;
import org.springframework.data.jdbc.core.conversion.DbAction.Insert; import org.springframework.data.jdbc.core.conversion.DbAction.Insert;
import org.springframework.data.jdbc.core.conversion.DbAction.Update; import org.springframework.data.jdbc.core.conversion.DbAction.Update;
import org.springframework.data.jdbc.core.conversion.DbChange.Kind;
import org.springframework.data.jdbc.mapping.model.JdbcMappingContext; import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
/** /**
@ -43,10 +43,10 @@ public class JdbcEntityWriterUnitTests {
public void newEntityGetsConvertedToOneInsert() { public void newEntityGetsConvertedToOneInsert() {
SomeEntity entity = new SomeEntity(null); SomeEntity entity = new SomeEntity(null);
DbChange<SomeEntity> dbChange = new DbChange(Kind.SAVE, SomeEntity.class, entity); AggregateChange<SomeEntity> aggregateChange = new AggregateChange(Kind.SAVE, SomeEntity.class, entity);
converter.write(entity, dbChange); converter.write(entity, aggregateChange);
assertThat(dbChange.getActions()).extracting(DbAction::getClass, DbAction::getEntityType) // assertThat(aggregateChange.getActions()).extracting(DbAction::getClass, DbAction::getEntityType) //
.containsExactly( // .containsExactly( //
tuple(Insert.class, SomeEntity.class) // tuple(Insert.class, SomeEntity.class) //
); );
@ -57,11 +57,11 @@ public class JdbcEntityWriterUnitTests {
SomeEntity entity = new SomeEntity(23L); SomeEntity entity = new SomeEntity(23L);
DbChange<SomeEntity> dbChange = new DbChange(Kind.SAVE, SomeEntity.class, entity); AggregateChange<SomeEntity> aggregateChange = new AggregateChange(Kind.SAVE, SomeEntity.class, entity);
converter.write(entity, dbChange); converter.write(entity, aggregateChange);
assertThat(dbChange.getActions()).extracting(DbAction::getClass, DbAction::getEntityType) // assertThat(aggregateChange.getActions()).extracting(DbAction::getClass, DbAction::getEntityType) //
.containsExactly( // .containsExactly( //
tuple(Delete.class, OtherEntity.class), // tuple(Delete.class, OtherEntity.class), //
tuple(Update.class, SomeEntity.class) // tuple(Update.class, SomeEntity.class) //
@ -74,11 +74,11 @@ public class JdbcEntityWriterUnitTests {
SomeEntity entity = new SomeEntity(23L); SomeEntity entity = new SomeEntity(23L);
entity.setOther(new OtherEntity(null)); entity.setOther(new OtherEntity(null));
DbChange<SomeEntity> dbChange = new DbChange(Kind.SAVE, SomeEntity.class, entity); AggregateChange<SomeEntity> aggregateChange = new AggregateChange(Kind.SAVE, SomeEntity.class, entity);
converter.write(entity, dbChange); converter.write(entity, aggregateChange);
assertThat(dbChange.getActions()).extracting(DbAction::getClass, DbAction::getEntityType) // assertThat(aggregateChange.getActions()).extracting(DbAction::getClass, DbAction::getEntityType) //
.containsExactly( // .containsExactly( //
tuple(Delete.class, OtherEntity.class), // tuple(Delete.class, OtherEntity.class), //
tuple(Update.class, SomeEntity.class), // tuple(Update.class, SomeEntity.class), //

Loading…
Cancel
Save