Skip to content

Commit 1f1753e

Browse files
schauderodrotbohm
authored andcommitted
DATAJDBC-98 - Update implemented.
New instances get saved with an insert statement. Existing instances get updated. Also added some test to find certain corner cases that I feared may cause problems: - ID properties being not editable (no setter and final). - ID properties being primitive. - ID properties not being named "id" and fixed the issues resulting from those. Original pull request: #5.
1 parent 21490b8 commit 1f1753e

File tree

7 files changed

+239
-89
lines changed

7 files changed

+239
-89
lines changed

src/main/java/org/springframework/data/jdbc/repository/SimpleJdbcRepository.java

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import javax.sql.DataSource;
2424
import org.springframework.data.jdbc.mapping.model.JdbcPersistentEntity;
2525
import org.springframework.data.jdbc.mapping.model.JdbcPersistentProperty;
26+
import org.springframework.data.jdbc.repository.support.JdbcPersistentEntityInformation;
2627
import org.springframework.data.mapping.PropertyHandler;
2728
import org.springframework.data.repository.CrudRepository;
2829
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
@@ -37,6 +38,7 @@
3738
public class SimpleJdbcRepository<T, ID extends Serializable> implements CrudRepository<T, ID> {
3839

3940
private final JdbcPersistentEntity<T> entity;
41+
private final JdbcPersistentEntityInformation<T,ID> entityInformation;
4042
private final NamedParameterJdbcOperations template;
4143
private final SqlGenerator sql;
4244

@@ -45,6 +47,7 @@ public class SimpleJdbcRepository<T, ID extends Serializable> implements CrudRep
4547
public SimpleJdbcRepository(JdbcPersistentEntity<T> entity, DataSource dataSource) {
4648

4749
this.entity = entity;
50+
this.entityInformation = new JdbcPersistentEntityInformation<T, ID>(entity);
4851
this.template = new NamedParameterJdbcTemplate(dataSource);
4952

5053
entityRowMapper = new EntityRowMapper<T>(entity);
@@ -54,14 +57,19 @@ public SimpleJdbcRepository(JdbcPersistentEntity<T> entity, DataSource dataSourc
5457
@Override
5558
public <S extends T> S save(S instance) {
5659

57-
KeyHolder holder = new GeneratedKeyHolder();
60+
if (entityInformation.isNew(instance)) {
5861

59-
template.update(
60-
sql.getInsert(),
61-
new MapSqlParameterSource(getPropertyMap(instance)),
62-
holder);
62+
KeyHolder holder = new GeneratedKeyHolder();
63+
64+
template.update(
65+
sql.getInsert(),
66+
new MapSqlParameterSource(getPropertyMap(instance)),
67+
holder);
6368

64-
entity.setId(instance, holder.getKey());
69+
entity.setId(instance, holder.getKey());
70+
} else {
71+
template.update(sql.getUpdate(), getPropertyMap(instance));
72+
}
6573

6674
return instance;
6775
}

src/main/java/org/springframework/data/jdbc/repository/SqlGenerator.java

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

1818
import java.util.ArrayList;
1919
import java.util.List;
20+
import java.util.stream.Collector;
2021
import java.util.stream.Collectors;
2122
import org.springframework.data.jdbc.mapping.model.JdbcPersistentEntity;
2223
import org.springframework.data.mapping.PropertyHandler;
@@ -37,9 +38,13 @@ class SqlGenerator {
3738
private final String deleteByIdSql;
3839
private final String deleteAllSql;
3940
private final String deleteByListSql;
41+
private final String updateSql;
42+
private final List<String> propertyNames = new ArrayList<>();
4043

4144
<T> SqlGenerator(JdbcPersistentEntity<T> entity) {
4245

46+
entity.doWithProperties((PropertyHandler) persistentProperty -> propertyNames.add(persistentProperty.getName()));
47+
4348
findOneSql = createFindOneSelectSql(entity);
4449
findAllSql = createFindAllSql(entity);
4550
findAllInListSql = createFindAllInListSql(entity);
@@ -48,6 +53,7 @@ <T> SqlGenerator(JdbcPersistentEntity<T> entity) {
4853
countSql = createCountSql(entity);
4954

5055
insertSql = createInsertSql(entity);
56+
updateSql = createUpdateSql(entity);
5157

5258
deleteByIdSql = createDeleteSql(entity);
5359
deleteAllSql = createDeleteAllSql(entity);
@@ -74,6 +80,10 @@ String getInsert() {
7480
return insertSql;
7581
}
7682

83+
String getUpdate() {
84+
return updateSql;
85+
}
86+
7787
String getCount() {
7888
return countSql;
7989
}
@@ -106,22 +116,26 @@ private String createExistsSql(JdbcPersistentEntity<?> entity) {
106116
}
107117

108118
private <T> String createCountSql(JdbcPersistentEntity<T> entity) {
109-
return String.format("select count(*) from %s", entity.getTableName(), entity.getIdColumn());
119+
return String.format("select count(*) from %s", entity.getTableName());
110120
}
111121

112122
private String createInsertSql(JdbcPersistentEntity<?> entity) {
113123

114-
List<String> propertyNames = new ArrayList<>();
115-
entity.doWithProperties((PropertyHandler) persistentProperty -> propertyNames.add(persistentProperty.getName()));
116-
117124
String insertTemplate = "insert into %s (%s) values (%s)";
118125

119-
String tableName = entity.getType().getSimpleName();
120-
121126
String tableColumns = propertyNames.stream().collect(Collectors.joining(", "));
122127
String parameterNames = propertyNames.stream().collect(Collectors.joining(", :", ":", ""));
123128

124-
return String.format(insertTemplate, tableName, tableColumns, parameterNames);
129+
return String.format(insertTemplate, entity.getTableName(), tableColumns, parameterNames);
130+
}
131+
132+
private <T> String createUpdateSql(JdbcPersistentEntity<T> entity) {
133+
134+
String updateTemplate = "update %s set %s where %s = :%s";
135+
136+
String setClause = propertyNames.stream().map(n -> String.format("%s = :%s", n, n)).collect(Collectors.joining(", "));
137+
138+
return String.format(updateTemplate, entity.getTableName(), setClause, entity.getIdColumn(), entity.getIdColumn());
125139
}
126140

127141
private String createDeleteSql(JdbcPersistentEntity entity) {
@@ -133,6 +147,7 @@ private String createDeleteAllSql(JdbcPersistentEntity entity) {
133147
}
134148

135149
private String createDeleteByListSql(JdbcPersistentEntity entity) {
136-
return String.format("delete from %s where id in (:ids)", entity.getTableName());
150+
return String.format("delete from %s where %s in (:ids)", entity.getTableName(), entity.getIdColumn());
137151
}
152+
138153
}
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/*
2+
* Copyright 2017 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.jdbc.repository;
17+
18+
import static org.assertj.core.api.Assertions.assertThat;
19+
import static org.junit.Assert.*;
20+
21+
import org.junit.After;
22+
import org.junit.Test;
23+
import org.springframework.data.annotation.Id;
24+
import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactory;
25+
import org.springframework.data.repository.CrudRepository;
26+
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
27+
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
28+
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
29+
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
30+
31+
import lombok.Data;
32+
33+
/**
34+
* testing special cases for Id generation with JdbcRepositories.
35+
*
36+
* @author Jens Schauder
37+
*/
38+
public class JdbcRepositoryIdGenerationIntegrationTests {
39+
40+
private final EmbeddedDatabase db = new EmbeddedDatabaseBuilder()
41+
.generateUniqueName(true)
42+
.setType(EmbeddedDatabaseType.HSQL)
43+
.setScriptEncoding("UTF-8")
44+
.ignoreFailedDrops(true)
45+
.addScript("org.springframework.data.jdbc.repository/jdbc-repository-id-generation-integration-tests.sql")
46+
.build();
47+
48+
private final NamedParameterJdbcTemplate template = new NamedParameterJdbcTemplate(db);
49+
50+
private final ReadOnlyIdEntityRepository repository = createRepository(db);
51+
52+
private ReadOnlyIdEntity entity = createDummyEntity();
53+
54+
@After
55+
public void after() {
56+
db.shutdown();
57+
}
58+
59+
@Test
60+
public void idWithoutSetterGetsSet() {
61+
62+
entity = repository.save(entity);
63+
64+
assertThat(entity.getId()).isNotNull();
65+
66+
ReadOnlyIdEntity reloadedEntity = repository.findOne(entity.getId());
67+
68+
assertEquals(
69+
entity.getId(),
70+
reloadedEntity.getId());
71+
assertEquals(
72+
entity.getName(),
73+
reloadedEntity.getName());
74+
}
75+
76+
@Test
77+
public void primitiveIdGetsSet() {
78+
79+
entity = repository.save(entity);
80+
81+
assertThat(entity.getId()).isNotNull();
82+
83+
ReadOnlyIdEntity reloadedEntity = repository.findOne(entity.getId());
84+
85+
assertEquals(
86+
entity.getId(),
87+
reloadedEntity.getId());
88+
assertEquals(
89+
entity.getName(),
90+
reloadedEntity.getName());
91+
}
92+
93+
94+
private static ReadOnlyIdEntityRepository createRepository(EmbeddedDatabase db) {
95+
return new JdbcRepositoryFactory(db).getRepository(ReadOnlyIdEntityRepository.class);
96+
}
97+
98+
99+
private static ReadOnlyIdEntity createDummyEntity() {
100+
101+
ReadOnlyIdEntity entity = new ReadOnlyIdEntity(null);
102+
entity.setName("Entity Name");
103+
return entity;
104+
}
105+
106+
private interface ReadOnlyIdEntityRepository extends CrudRepository<ReadOnlyIdEntity, Long> {
107+
108+
}
109+
110+
@Data
111+
static class ReadOnlyIdEntity {
112+
113+
@Id
114+
private final Long id;
115+
String name;
116+
}
117+
118+
private interface PrimitiveIdEntityRepository extends CrudRepository<PrimitiveIdEntity, Long> {
119+
120+
}
121+
122+
@Data
123+
static class PrimitiveIdEntity {
124+
125+
@Id
126+
private final Long id;
127+
String name;
128+
}
129+
}

0 commit comments

Comments
 (0)