Skip to content

Commit 7ae92d3

Browse files
committed
Add support for selectKey and generated keys in update statements
1 parent ec1e827 commit 7ae92d3

File tree

6 files changed

+237
-9
lines changed

6 files changed

+237
-9
lines changed

src/main/java/org/apache/ibatis/builder/annotation/MapperAnnotationBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ void parseStatement(Method method) {
257257
KeyGenerator keyGenerator;
258258
String keyProperty = "id";
259259
String keyColumn = null;
260-
if (SqlCommandType.INSERT.equals(sqlCommandType)) {
260+
if (SqlCommandType.INSERT.equals(sqlCommandType) || SqlCommandType.UPDATE.equals(sqlCommandType)) {
261261
// first check for SelectKey annotation - that overrides everything else
262262
SelectKey selectKey = method.getAnnotation(SelectKey.class);
263263
if (selectKey != null) {

src/main/java/org/apache/ibatis/builder/xml/XMLStatementBuilder.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ private void parseSelectKeyNode(String id, XNode nodeToHandle, Class<?> paramete
131131
Class<?> resultTypeClass = resolveClass(resultType);
132132
StatementType statementType = StatementType.valueOf(nodeToHandle.getStringAttribute("statementType", StatementType.PREPARED.toString()));
133133
String keyProperty = nodeToHandle.getStringAttribute("keyProperty");
134+
String keyColumn = nodeToHandle.getStringAttribute("keyColumn");
134135
boolean executeBefore = "BEFORE".equals(nodeToHandle.getStringAttribute("order", "AFTER"));
135136

136137
//defaults
@@ -150,7 +151,7 @@ private void parseSelectKeyNode(String id, XNode nodeToHandle, Class<?> paramete
150151
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,
151152
fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,
152153
resultSetTypeEnum, flushCache, useCache, resultOrdered,
153-
keyGenerator, keyProperty, null, databaseId, langDriver, null);
154+
keyGenerator, keyProperty, keyColumn, databaseId, langDriver, null);
154155

155156
id = builderAssistant.applyCurrentNamespace(id, false);
156157

src/main/java/org/apache/ibatis/builder/xml/mybatis-3-mapper.dtd

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,18 +203,22 @@ lang CDATA #IMPLIED
203203
resultType CDATA #IMPLIED
204204
statementType (STATEMENT|PREPARED|CALLABLE) #IMPLIED
205205
keyProperty CDATA #IMPLIED
206+
keyColumn CDATA #IMPLIED
206207
order (BEFORE|AFTER) #IMPLIED
207208
databaseId CDATA #IMPLIED
208209
>
209210

210-
<!ELEMENT update (#PCDATA | include | trim | where | set | foreach | choose | if | bind)*>
211+
<!ELEMENT update (#PCDATA | selectKey | include | trim | where | set | foreach | choose | if | bind)*>
211212
<!ATTLIST update
212213
id CDATA #REQUIRED
213214
parameterMap CDATA #IMPLIED
214215
parameterType CDATA #IMPLIED
215216
timeout CDATA #IMPLIED
216217
flushCache (true|false) #IMPLIED
217218
statementType (STATEMENT|PREPARED|CALLABLE) #IMPLIED
219+
keyProperty CDATA #IMPLIED
220+
useGeneratedKeys (true|false) #IMPLIED
221+
keyColumn CDATA #IMPLIED
218222
databaseId CDATA #IMPLIED
219223
lang CDATA #IMPLIED
220224
>

src/main/java/org/apache/ibatis/executor/keygen/SelectKeyGenerator.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,16 @@ private void processGeneratedKeys(Executor executor, MappedStatement ms, Object
6565
} else if (values.size() > 1) {
6666
throw new ExecutorException("SelectKey returned more than one value.");
6767
} else {
68+
MetaObject metaResult = configuration.newMetaObject(values.get(0));
6869
if (keyProperties.length == 1) {
69-
setValue(metaParam, keyProperties[0], values.get(0));
70+
if (metaResult.hasGetter(keyProperties[0])) {
71+
setValue(metaParam, keyProperties[0], metaResult.getValue(keyProperties[0]));
72+
} else {
73+
// no getter for the property - maybe just a single value object
74+
// so try that
75+
setValue(metaParam, keyProperties[0], values.get(0));
76+
}
7077
} else {
71-
MetaObject metaResult = configuration.newMetaObject(values.get(0));
7278
handleMultipleProperties(keyProperties, metaParam, metaResult);
7379
}
7480
}

src/test/java/org/apache/ibatis/submitted/selectkey/AnnotatedMapper.java

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import org.apache.ibatis.annotations.InsertProvider;
2222
import org.apache.ibatis.annotations.Options;
2323
import org.apache.ibatis.annotations.SelectKey;
24+
import org.apache.ibatis.annotations.Update;
2425

2526
public interface AnnotatedMapper {
2627

@@ -30,21 +31,45 @@ public interface AnnotatedMapper {
3031

3132
@Insert("insert into table2 (name) values(#{name})")
3233
@Options(useGeneratedKeys=true, keyProperty="nameId,generatedName", keyColumn="ID,NAME_FRED")
33-
int insertTable2WithOptions(Name name);
34+
int insertTable2WithGeneratedKey(Name name);
3435

36+
int insertTable2WithGeneratedKeyXml(Name name);
37+
3538
@Insert("insert into table2 (name) values(#{name})")
3639
@SelectKey(statement="select id, name_fred from table2 where id = identity()", keyProperty="nameId,generatedName", keyColumn="ID,NAME_FRED", before=false, resultType=Map.class)
3740
int insertTable2WithSelectKeyWithKeyMap(Name name);
3841

42+
int insertTable2WithSelectKeyWithKeyMapXml(Name name);
43+
3944
@Insert("insert into table2 (name) values(#{name})")
4045
@SelectKey(statement="select id as nameId, name_fred as generatedName from table2 where id = identity()", keyProperty="nameId,generatedName", before=false, resultType=Name.class)
4146
int insertTable2WithSelectKeyWithKeyObject(Name name);
4247

48+
int insertTable2WithSelectKeyWithKeyObjectXml(Name name);
49+
4350
@Insert("insert into table3 (id, name) values(#{nameId}, #{name})")
4451
@SelectKey(statement="call next value for TestSequence", keyProperty="nameId", before=true, resultType=int.class)
4552
int insertTable3(Name name);
4653

4754
@InsertProvider(type=SqlProvider.class,method="insertTable3_2")
4855
@SelectKey(statement="call next value for TestSequence", keyProperty="nameId", before=true, resultType=int.class)
4956
int insertTable3_2(Name name);
57+
58+
@Update("update table2 set name = #{name} where id = #{nameId}")
59+
@Options(useGeneratedKeys=true, keyProperty="generatedName")
60+
int updateTable2WithGeneratedKey(Name name);
61+
62+
int updateTable2WithGeneratedKeyXml(Name name);
63+
64+
@Update("update table2 set name = #{name} where id = #{nameId}")
65+
@SelectKey(statement="select name_fred from table2 where id = #{nameId}", keyProperty="generatedName", keyColumn="NAME_FRED", before=false, resultType=String.class)
66+
int updateTable2WithSelectKeyWithKeyMap(Name name);
67+
68+
int updateTable2WithSelectKeyWithKeyMapXml(Name name);
69+
70+
@Update("update table2 set name = #{name} where id = #{nameId}")
71+
@SelectKey(statement="select name_fred as generatedName from table2 where id = #{nameId}", keyProperty="generatedName", before=false, resultType=Name.class)
72+
int updateTable2WithSelectKeyWithKeyObject(Name name);
73+
74+
int updateTable2WithSelectKeyWithKeyObjectXml(Name name);
5075
}

src/test/java/org/apache/ibatis/submitted/selectkey/SelectKeyTest.java

Lines changed: 195 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,11 @@
2121
import org.apache.ibatis.session.SqlSession;
2222
import org.apache.ibatis.session.SqlSessionFactory;
2323
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
24-
import static org.junit.Assert.assertEquals;
24+
2525
import static org.junit.Assert.*;
2626

2727
import org.junit.Before;
28+
import org.junit.Ignore;
2829
import org.junit.Test;
2930

3031
import java.io.Reader;
@@ -153,14 +154,79 @@ public void testAnnotatedInsertTable2() {
153154
}
154155

155156
@Test
156-
public void testAnnotatedInsertTable2WithOptions() {
157+
public void testAnnotatedInsertTable2WithGeneratedKey() {
158+
SqlSession sqlSession = sqlSessionFactory.openSession();
159+
160+
try {
161+
Name name = new Name();
162+
name.setName("barney");
163+
AnnotatedMapper mapper = sqlSession.getMapper(AnnotatedMapper.class);
164+
int rows = mapper.insertTable2WithGeneratedKey(name);
165+
assertEquals(1, rows);
166+
assertEquals(22, name.getNameId());
167+
assertEquals("barney_fred", name.getGeneratedName());
168+
} finally {
169+
sqlSession.close();
170+
}
171+
}
172+
173+
@Test
174+
@Ignore("HSQLDB is not returning the generated column after the update")
175+
public void testAnnotatedUpdateTable2WithGeneratedKey() {
157176
SqlSession sqlSession = sqlSessionFactory.openSession();
158177

159178
try {
160179
Name name = new Name();
161180
name.setName("barney");
162181
AnnotatedMapper mapper = sqlSession.getMapper(AnnotatedMapper.class);
163-
int rows = mapper.insertTable2WithOptions(name);
182+
int rows = mapper.insertTable2WithGeneratedKey(name);
183+
assertEquals(1, rows);
184+
assertEquals(22, name.getNameId());
185+
assertEquals("barney_fred", name.getGeneratedName());
186+
187+
name.setName("Wilma");
188+
rows = mapper.updateTable2WithGeneratedKey(name);
189+
assertEquals(1, rows);
190+
assertEquals(22, name.getNameId());
191+
assertEquals("Wilma_fred", name.getGeneratedName());
192+
} finally {
193+
sqlSession.close();
194+
}
195+
}
196+
197+
@Test
198+
@Ignore("HSQLDB is not returning the generated column after the update")
199+
public void testAnnotatedUpdateTable2WithGeneratedKeyXml() {
200+
SqlSession sqlSession = sqlSessionFactory.openSession();
201+
202+
try {
203+
Name name = new Name();
204+
name.setName("barney");
205+
AnnotatedMapper mapper = sqlSession.getMapper(AnnotatedMapper.class);
206+
int rows = mapper.insertTable2WithGeneratedKeyXml(name);
207+
assertEquals(1, rows);
208+
assertEquals(22, name.getNameId());
209+
assertEquals("barney_fred", name.getGeneratedName());
210+
211+
name.setName("Wilma");
212+
rows = mapper.updateTable2WithGeneratedKeyXml(name);
213+
assertEquals(1, rows);
214+
assertEquals(22, name.getNameId());
215+
assertEquals("Wilma_fred", name.getGeneratedName());
216+
} finally {
217+
sqlSession.close();
218+
}
219+
}
220+
221+
@Test
222+
public void testAnnotatedInsertTable2WithGeneratedKeyXml() {
223+
SqlSession sqlSession = sqlSessionFactory.openSession();
224+
225+
try {
226+
Name name = new Name();
227+
name.setName("barney");
228+
AnnotatedMapper mapper = sqlSession.getMapper(AnnotatedMapper.class);
229+
int rows = mapper.insertTable2WithGeneratedKeyXml(name);
164230
assertEquals(1, rows);
165231
assertEquals(22, name.getNameId());
166232
assertEquals("barney_fred", name.getGeneratedName());
@@ -186,6 +252,69 @@ public void testAnnotatedInsertTable2WithSelectKeyWithKeyMap() {
186252
}
187253
}
188254

255+
@Test
256+
public void testAnnotatedUpdateTable2WithSelectKeyWithKeyMap() {
257+
SqlSession sqlSession = sqlSessionFactory.openSession();
258+
259+
try {
260+
Name name = new Name();
261+
name.setName("barney");
262+
AnnotatedMapper mapper = sqlSession.getMapper(AnnotatedMapper.class);
263+
int rows = mapper.insertTable2WithSelectKeyWithKeyMap(name);
264+
assertEquals(1, rows);
265+
assertEquals(22, name.getNameId());
266+
assertEquals("barney_fred", name.getGeneratedName());
267+
268+
name.setName("Wilma");
269+
rows = mapper.updateTable2WithSelectKeyWithKeyMap(name);
270+
assertEquals(1, rows);
271+
assertEquals(22, name.getNameId());
272+
assertEquals("Wilma_fred", name.getGeneratedName());
273+
} finally {
274+
sqlSession.close();
275+
}
276+
}
277+
278+
@Test
279+
public void testAnnotatedInsertTable2WithSelectKeyWithKeyMapXml() {
280+
SqlSession sqlSession = sqlSessionFactory.openSession();
281+
282+
try {
283+
Name name = new Name();
284+
name.setName("barney");
285+
AnnotatedMapper mapper = sqlSession.getMapper(AnnotatedMapper.class);
286+
int rows = mapper.insertTable2WithSelectKeyWithKeyMapXml(name);
287+
assertEquals(1, rows);
288+
assertEquals(22, name.getNameId());
289+
assertEquals("barney_fred", name.getGeneratedName());
290+
} finally {
291+
sqlSession.close();
292+
}
293+
}
294+
295+
@Test
296+
public void testAnnotatedUpdateTable2WithSelectKeyWithKeyMapXml() {
297+
SqlSession sqlSession = sqlSessionFactory.openSession();
298+
299+
try {
300+
Name name = new Name();
301+
name.setName("barney");
302+
AnnotatedMapper mapper = sqlSession.getMapper(AnnotatedMapper.class);
303+
int rows = mapper.insertTable2WithSelectKeyWithKeyMapXml(name);
304+
assertEquals(1, rows);
305+
assertEquals(22, name.getNameId());
306+
assertEquals("barney_fred", name.getGeneratedName());
307+
308+
name.setName("Wilma");
309+
rows = mapper.updateTable2WithSelectKeyWithKeyMapXml(name);
310+
assertEquals(1, rows);
311+
assertEquals(22, name.getNameId());
312+
assertEquals("Wilma_fred", name.getGeneratedName());
313+
} finally {
314+
sqlSession.close();
315+
}
316+
}
317+
189318
@Test
190319
public void testAnnotatedInsertTable2WithSelectKeyWithKeyObject() {
191320
SqlSession sqlSession = sqlSessionFactory.openSession();
@@ -203,6 +332,69 @@ public void testAnnotatedInsertTable2WithSelectKeyWithKeyObject() {
203332
}
204333
}
205334

335+
@Test
336+
public void testAnnotatedUpdateTable2WithSelectKeyWithKeyObject() {
337+
SqlSession sqlSession = sqlSessionFactory.openSession();
338+
339+
try {
340+
Name name = new Name();
341+
name.setName("barney");
342+
AnnotatedMapper mapper = sqlSession.getMapper(AnnotatedMapper.class);
343+
int rows = mapper.insertTable2WithSelectKeyWithKeyObject(name);
344+
assertEquals(1, rows);
345+
assertEquals(22, name.getNameId());
346+
assertEquals("barney_fred", name.getGeneratedName());
347+
348+
name.setName("Wilma");
349+
rows = mapper.updateTable2WithSelectKeyWithKeyObject(name);
350+
assertEquals(1, rows);
351+
assertEquals(22, name.getNameId());
352+
assertEquals("Wilma_fred", name.getGeneratedName());
353+
} finally {
354+
sqlSession.close();
355+
}
356+
}
357+
358+
@Test
359+
public void testAnnotatedUpdateTable2WithSelectKeyWithKeyObjectXml() {
360+
SqlSession sqlSession = sqlSessionFactory.openSession();
361+
362+
try {
363+
Name name = new Name();
364+
name.setName("barney");
365+
AnnotatedMapper mapper = sqlSession.getMapper(AnnotatedMapper.class);
366+
int rows = mapper.insertTable2WithSelectKeyWithKeyObjectXml(name);
367+
assertEquals(1, rows);
368+
assertEquals(22, name.getNameId());
369+
assertEquals("barney_fred", name.getGeneratedName());
370+
371+
name.setName("Wilma");
372+
rows = mapper.updateTable2WithSelectKeyWithKeyObjectXml(name);
373+
assertEquals(1, rows);
374+
assertEquals(22, name.getNameId());
375+
assertEquals("Wilma_fred", name.getGeneratedName());
376+
} finally {
377+
sqlSession.close();
378+
}
379+
}
380+
381+
@Test
382+
public void testAnnotatedInsertTable2WithSelectKeyWithKeyObjectXml() {
383+
SqlSession sqlSession = sqlSessionFactory.openSession();
384+
385+
try {
386+
Name name = new Name();
387+
name.setName("barney");
388+
AnnotatedMapper mapper = sqlSession.getMapper(AnnotatedMapper.class);
389+
int rows = mapper.insertTable2WithSelectKeyWithKeyObjectXml(name);
390+
assertEquals(1, rows);
391+
assertEquals(22, name.getNameId());
392+
assertEquals("barney_fred", name.getGeneratedName());
393+
} finally {
394+
sqlSession.close();
395+
}
396+
}
397+
206398
@Test
207399
public void testAnnotatedInsertTable3() {
208400
SqlSession sqlSession = sqlSessionFactory.openSession();

0 commit comments

Comments
 (0)