Skip to content

Commit eb2d270

Browse files
committed
DATAJDBC-227 - Refactored JdbcEntityWriter and DbActions.
JdbcEntityWriter and JdbcDeleteEntityWriter now use an iterative approach based on PersistentPropertyPath instead of a recursive one. DbAction is now split into multiple interfaces representing different variants of actions. The implementations are simple value types without any implementation inheritance hierarchy. All elements of a DbAction implementation are not null making usage and construction of instances much easier.
1 parent 31f3f2f commit eb2d270

30 files changed

+875
-757
lines changed

src/main/java/org/springframework/data/jdbc/core/CascadingDataAccessStrategy.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
import java.util.function.Consumer;
2222
import java.util.function.Function;
2323

24-
import org.springframework.data.mapping.PropertyPath;
24+
import org.springframework.data.mapping.PersistentPropertyPath;
2525
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
2626

2727
/**
@@ -45,8 +45,8 @@ public <T> void insert(T instance, Class<T> domainType, Map<String, Object> addi
4545
}
4646

4747
@Override
48-
public <S> void update(S instance, Class<S> domainType) {
49-
collectVoid(das -> das.update(instance, domainType));
48+
public <S> boolean update(S instance, Class<S> domainType) {
49+
return collect(das -> das.update(instance, domainType));
5050
}
5151

5252
@Override
@@ -55,7 +55,7 @@ public void delete(Object id, Class<?> domainType) {
5555
}
5656

5757
@Override
58-
public void delete(Object rootId, PropertyPath propertyPath) {
58+
public void delete(Object rootId, PersistentPropertyPath<RelationalPersistentProperty> propertyPath) {
5959
collectVoid(das -> das.delete(rootId, propertyPath));
6060
}
6161

@@ -65,7 +65,7 @@ public <T> void deleteAll(Class<T> domainType) {
6565
}
6666

6767
@Override
68-
public void deleteAll(PropertyPath propertyPath) {
68+
public void deleteAll(PersistentPropertyPath<RelationalPersistentProperty> propertyPath) {
6969
collectVoid(das -> das.deleteAll(propertyPath));
7070
}
7171

src/main/java/org/springframework/data/jdbc/core/DataAccessStrategy.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
import java.util.Map;
1919

20-
import org.springframework.data.mapping.PropertyPath;
20+
import org.springframework.data.mapping.PersistentPropertyPath;
2121
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
2222
import org.springframework.lang.Nullable;
2323

@@ -48,8 +48,9 @@ public interface DataAccessStrategy {
4848
* @param instance the instance to save. Must not be {@code null}.
4949
* @param domainType the type of the instance to save. Must not be {@code null}.
5050
* @param <T> the type of the instance to save.
51+
* @return wether the update actually updated a row.
5152
*/
52-
<T> void update(T instance, Class<T> domainType);
53+
<T> boolean update(T instance, Class<T> domainType);
5354

5455
/**
5556
* deletes a single row identified by the id, from the table identified by the domainType. Does not handle cascading
@@ -63,11 +64,11 @@ public interface DataAccessStrategy {
6364

6465
/**
6566
* Deletes all entities reachable via {@literal propertyPath} from the instance identified by {@literal rootId}.
66-
*
67+
*
6768
* @param rootId Id of the root object on which the {@literal propertyPath} is based. Must not be {@code null}.
6869
* @param propertyPath Leading from the root object to the entities to be deleted. Must not be {@code null}.
6970
*/
70-
void delete(Object rootId, PropertyPath propertyPath);
71+
void delete(Object rootId, PersistentPropertyPath<RelationalPersistentProperty> propertyPath);
7172

7273
/**
7374
* Deletes all entities of the given domain type.
@@ -82,7 +83,7 @@ public interface DataAccessStrategy {
8283
*
8384
* @param propertyPath Leading from the root object to the entities to be deleted. Must not be {@code null}.
8485
*/
85-
void deleteAll(PropertyPath propertyPath);
86+
void deleteAll(PersistentPropertyPath<RelationalPersistentProperty> propertyPath);
8687

8788
/**
8889
* Counts the rows in the table representing the given domain type.

src/main/java/org/springframework/data/jdbc/core/DefaultDataAccessStrategy.java

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@
3030
import org.springframework.data.convert.EntityInstantiators;
3131
import org.springframework.data.jdbc.support.JdbcUtil;
3232
import org.springframework.data.mapping.PersistentPropertyAccessor;
33+
import org.springframework.data.mapping.PersistentPropertyPath;
3334
import org.springframework.data.mapping.PropertyHandler;
34-
import org.springframework.data.mapping.PropertyPath;
3535
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
3636
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
3737
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
@@ -118,11 +118,11 @@ public <T> void insert(T instance, Class<T> domainType, Map<String, Object> addi
118118
* @see org.springframework.data.jdbc.core.DataAccessStrategy#update(java.lang.Object, java.lang.Class)
119119
*/
120120
@Override
121-
public <S> void update(S instance, Class<S> domainType) {
121+
public <S> boolean update(S instance, Class<S> domainType) {
122122

123123
RelationalPersistentEntity<S> persistentEntity = getRequiredPersistentEntity(domainType);
124124

125-
operations.update(sql(domainType).getUpdate(), getPropertyMap(instance, persistentEntity));
125+
return operations.update(sql(domainType).getUpdate(), getPropertyMap(instance, persistentEntity)) != 0;
126126
}
127127

128128
/*
@@ -143,11 +143,12 @@ public void delete(Object id, Class<?> domainType) {
143143
* @see org.springframework.data.jdbc.core.DataAccessStrategy#delete(java.lang.Object, org.springframework.data.mapping.PropertyPath)
144144
*/
145145
@Override
146-
public void delete(Object rootId, PropertyPath propertyPath) {
146+
public void delete(Object rootId, PersistentPropertyPath<RelationalPersistentProperty> propertyPath) {
147147

148-
RelationalPersistentEntity<?> rootEntity = context.getRequiredPersistentEntity(propertyPath.getOwningType());
148+
RelationalPersistentEntity<?> rootEntity = context
149+
.getRequiredPersistentEntity(propertyPath.getBaseProperty().getOwner().getType());
149150

150-
RelationalPersistentProperty referencingProperty = rootEntity.getRequiredPersistentProperty(propertyPath.getSegment());
151+
RelationalPersistentProperty referencingProperty = propertyPath.getLeafProperty();
151152
Assert.notNull(referencingProperty, "No property found matching the PropertyPath " + propertyPath);
152153

153154
String format = sql(rootEntity.getType()).createDeleteByPath(propertyPath);
@@ -171,8 +172,9 @@ public <T> void deleteAll(Class<T> domainType) {
171172
* @see org.springframework.data.jdbc.core.DataAccessStrategy#deleteAll(org.springframework.data.mapping.PropertyPath)
172173
*/
173174
@Override
174-
public void deleteAll(PropertyPath propertyPath) {
175-
operations.getJdbcOperations().update(sql(propertyPath.getOwningType().getType()).createDeleteAllSql(propertyPath));
175+
public void deleteAll(PersistentPropertyPath<RelationalPersistentProperty> propertyPath) {
176+
operations.getJdbcOperations()
177+
.update(sql(propertyPath.getBaseProperty().getOwner().getType()).createDeleteAllSql(propertyPath));
176178
}
177179

178180
/*
@@ -318,8 +320,8 @@ private <S> void setIdFromJdbc(S instance, KeyHolder holder, RelationalPersisten
318320

319321
getIdFromHolder(holder, persistentEntity).ifPresent(it -> {
320322

321-
PersistentPropertyAccessor accessor = persistentEntity.getPropertyAccessor(instance);
322-
ConvertingPropertyAccessor convertingPropertyAccessor = new ConvertingPropertyAccessor(accessor,
323+
PersistentPropertyAccessor<S> accessor = persistentEntity.getPropertyAccessor(instance);
324+
ConvertingPropertyAccessor<S> convertingPropertyAccessor = new ConvertingPropertyAccessor<>(accessor,
323325
context.getConversions());
324326
RelationalPersistentProperty idProperty = persistentEntity.getRequiredIdProperty();
325327

@@ -339,7 +341,10 @@ private <S> Optional<Object> getIdFromHolder(KeyHolder holder, RelationalPersist
339341
} catch (InvalidDataAccessApiUsageException e) {
340342
// Postgres returns a value for each column
341343
Map<String, Object> keys = holder.getKeys();
342-
return Optional.ofNullable(keys == null ? null : keys.get(persistentEntity.getIdColumn()));
344+
return Optional.ofNullable( //
345+
keys == null || persistentEntity.getIdProperty() == null //
346+
? null //
347+
: keys.get(persistentEntity.getIdColumn()));
343348
}
344349
}
345350

src/main/java/org/springframework/data/jdbc/core/DefaultJdbcInterpreter.java

Lines changed: 47 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,22 @@
1818
import java.util.HashMap;
1919
import java.util.Map;
2020

21-
import org.springframework.data.mapping.PropertyPath;
21+
import org.springframework.data.mapping.PersistentPropertyPath;
2222
import org.springframework.data.relational.core.conversion.DbAction;
23-
import org.springframework.data.relational.core.conversion.Interpreter;
2423
import org.springframework.data.relational.core.conversion.DbAction.Delete;
2524
import org.springframework.data.relational.core.conversion.DbAction.DeleteAll;
25+
import org.springframework.data.relational.core.conversion.DbAction.DeleteAllRoot;
26+
import org.springframework.data.relational.core.conversion.DbAction.DeleteRoot;
2627
import org.springframework.data.relational.core.conversion.DbAction.Insert;
28+
import org.springframework.data.relational.core.conversion.DbAction.InsertRoot;
29+
import org.springframework.data.relational.core.conversion.DbAction.Merge;
2730
import org.springframework.data.relational.core.conversion.DbAction.Update;
31+
import org.springframework.data.relational.core.conversion.DbAction.UpdateRoot;
32+
import org.springframework.data.relational.core.conversion.Interpreter;
2833
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
2934
import org.springframework.data.relational.core.mapping.RelationalPersistentEntity;
35+
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
3036
import org.springframework.lang.Nullable;
31-
import org.springframework.util.Assert;
3237

3338
/**
3439
* {@link Interpreter} for {@link DbAction}s using a {@link DataAccessStrategy} for performing actual database
@@ -53,68 +58,80 @@ public <T> void interpret(Insert<T> insert) {
5358
accessStrategy.insert(insert.getEntity(), insert.getEntityType(), createAdditionalColumnValues(insert));
5459
}
5560

61+
@Override
62+
public <T> void interpret(InsertRoot<T> insert) {
63+
accessStrategy.insert(insert.getEntity(), insert.getEntityType(), new HashMap<>());
64+
}
65+
5666
@Override
5767
public <T> void interpret(Update<T> update) {
5868
accessStrategy.update(update.getEntity(), update.getEntityType());
5969
}
6070

6171
@Override
62-
public <T> void interpret(Delete<T> delete) {
72+
public <T> void interpret(UpdateRoot<T> update) {
73+
accessStrategy.update(update.getEntity(), update.getEntityType());
74+
}
75+
76+
@Override
77+
public <T> void interpret(Merge<T> merge) {
6378

64-
if (delete.getPropertyPath() == null) {
65-
accessStrategy.delete(delete.getRootId(), delete.getEntityType());
66-
} else {
67-
accessStrategy.delete(delete.getRootId(), delete.getPropertyPath().getPath());
79+
// temporary implementation
80+
if (!accessStrategy.update(merge.getEntity(), merge.getEntityType())) {
81+
accessStrategy.insert(merge.getEntity(), merge.getEntityType(), createAdditionalColumnValues(merge));
6882
}
6983
}
7084

85+
@Override
86+
public <T> void interpret(Delete<T> delete) {
87+
accessStrategy.delete(delete.getRootId(), delete.getPropertyPath());
88+
}
89+
90+
@Override
91+
public <T> void interpret(DeleteRoot<T> delete) {
92+
accessStrategy.delete(delete.getRootId(), delete.getEntityType());
93+
}
94+
7195
@Override
7296
public <T> void interpret(DeleteAll<T> delete) {
97+
accessStrategy.deleteAll(delete.getPropertyPath());
98+
}
7399

74-
if (delete.getEntityType() == null) {
75-
accessStrategy.deleteAll(delete.getPropertyPath().getPath());
76-
} else {
77-
accessStrategy.deleteAll(delete.getEntityType());
78-
}
100+
@Override
101+
public <T> void interpret(DeleteAllRoot<T> deleteAllRoot) {
102+
accessStrategy.deleteAll(deleteAllRoot.getEntityType());
79103
}
80104

81-
private <T> Map<String, Object> createAdditionalColumnValues(Insert<T> insert) {
105+
private <T> Map<String, Object> createAdditionalColumnValues(DbAction.WithDependingOn<T> action) {
82106

83107
Map<String, Object> additionalColumnValues = new HashMap<>();
84-
addDependingOnInformation(insert, additionalColumnValues);
85-
additionalColumnValues.putAll(insert.getAdditionalValues());
108+
addDependingOnInformation(action, additionalColumnValues);
109+
additionalColumnValues.putAll(action.getAdditionalValues());
86110

87111
return additionalColumnValues;
88112
}
89113

90-
private <T> void addDependingOnInformation(Insert<T> insert, Map<String, Object> additionalColumnValues) {
91-
92-
DbAction dependingOn = insert.getDependingOn();
114+
private <T> void addDependingOnInformation(DbAction.WithDependingOn<T> action, Map<String, Object> additionalColumnValues) {
93115

94-
if (dependingOn == null) {
95-
return;
96-
}
116+
DbAction.WithEntity<?> dependingOn = action.getDependingOn();
97117

98118
RelationalPersistentEntity<?> persistentEntity = context.getRequiredPersistentEntity(dependingOn.getEntityType());
99119

100-
String columnName = getColumnNameForReverseColumn(insert, persistentEntity);
120+
String columnName = getColumnNameForReverseColumn(action);
101121

102122
Object identifier = getIdFromEntityDependingOn(dependingOn, persistentEntity);
103123

104124
additionalColumnValues.put(columnName, identifier);
105125
}
106126

107127
@Nullable
108-
private Object getIdFromEntityDependingOn(DbAction dependingOn, RelationalPersistentEntity<?> persistentEntity) {
128+
private Object getIdFromEntityDependingOn(DbAction.WithEntity<?> dependingOn, RelationalPersistentEntity<?> persistentEntity) {
109129
return persistentEntity.getIdentifierAccessor(dependingOn.getEntity()).getIdentifier();
110130
}
111131

112-
private <T> String getColumnNameForReverseColumn(Insert<T> insert, RelationalPersistentEntity<?> persistentEntity) {
113-
114-
PropertyPath path = insert.getPropertyPath().getPath();
115-
116-
Assert.notNull(path, "There shouldn't be an insert depending on another insert without having a PropertyPath.");
132+
private String getColumnNameForReverseColumn(DbAction.WithPropertyPath<?> action) {
117133

118-
return persistentEntity.getRequiredPersistentProperty(path.getSegment()).getReverseColumnName();
134+
PersistentPropertyPath<RelationalPersistentProperty> path = action.getPropertyPath();
135+
return path.getRequiredLeafProperty().getReverseColumnName();
119136
}
120137
}

src/main/java/org/springframework/data/jdbc/core/DelegatingDataAccessStrategy.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
import java.util.Map;
1919

20-
import org.springframework.data.mapping.PropertyPath;
20+
import org.springframework.data.mapping.PersistentPropertyPath;
2121
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
2222
import org.springframework.util.Assert;
2323

@@ -38,12 +38,12 @@ public <T> void insert(T instance, Class<T> domainType, Map<String, Object> addi
3838
}
3939

4040
@Override
41-
public <S> void update(S instance, Class<S> domainType) {
42-
delegate.update(instance, domainType);
41+
public <S> boolean update(S instance, Class<S> domainType) {
42+
return delegate.update(instance, domainType);
4343
}
4444

4545
@Override
46-
public void delete(Object rootId, PropertyPath propertyPath) {
46+
public void delete(Object rootId, PersistentPropertyPath<RelationalPersistentProperty> propertyPath) {
4747
delegate.delete(rootId, propertyPath);
4848
}
4949

@@ -58,7 +58,7 @@ public <T> void deleteAll(Class<T> domainType) {
5858
}
5959

6060
@Override
61-
public void deleteAll(PropertyPath propertyPath) {
61+
public void deleteAll(PersistentPropertyPath<RelationalPersistentProperty> propertyPath) {
6262
delegate.deleteAll(propertyPath);
6363
}
6464

0 commit comments

Comments
 (0)