Skip to content

Commit ec1e827

Browse files
committed
Support multiple key properties in @SelectKey
1 parent 869f951 commit ec1e827

File tree

5 files changed

+82
-6
lines changed

5 files changed

+82
-6
lines changed

src/main/java/org/apache/ibatis/annotations/SelectKey.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929

3030
String keyProperty();
3131

32+
String keyColumn() default "";
33+
3234
boolean before();
3335

3436
Class<?> resultType();

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,7 @@ private KeyGenerator handleSelectKeyAnnotation(SelectKey selectKeyAnnotation, St
564564
Class<?> resultTypeClass = selectKeyAnnotation.resultType();
565565
StatementType statementType = selectKeyAnnotation.statementType();
566566
String keyProperty = selectKeyAnnotation.keyProperty();
567+
String keyColumn = selectKeyAnnotation.keyColumn();
567568
boolean executeBefore = selectKeyAnnotation.before();
568569

569570
// defaults
@@ -581,7 +582,7 @@ private KeyGenerator handleSelectKeyAnnotation(SelectKey selectKeyAnnotation, St
581582

582583
assistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum,
583584
flushCache, useCache, false,
584-
keyGenerator, keyProperty, null, null, languageDriver, null);
585+
keyGenerator, keyProperty, keyColumn, null, languageDriver, null);
585586

586587
id = assistant.applyCurrentNamespace(id, false);
587588

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

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,10 @@ public void processAfter(Executor executor, MappedStatement ms, Statement stmt,
5252
private void processGeneratedKeys(Executor executor, MappedStatement ms, Object parameter) {
5353
try {
5454
if (parameter != null && keyStatement != null && keyStatement.getKeyProperties() != null) {
55-
String keyProperty = keyStatement.getKeyProperties()[0]; // just one key property is supported
55+
String[] keyProperties = keyStatement.getKeyProperties();
5656
final Configuration configuration = ms.getConfiguration();
5757
final MetaObject metaParam = configuration.newMetaObject(parameter);
58-
if (keyProperty != null && metaParam.hasSetter(keyProperty)) {
58+
if (keyProperties != null) {
5959
// Do not close keyExecutor.
6060
// The transaction will be closed by parent executor.
6161
Executor keyExecutor = configuration.newExecutor(executor.getTransaction(), ExecutorType.SIMPLE);
@@ -65,10 +65,13 @@ 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-
metaParam.setValue(keyProperty, values.get(0));
68+
if (keyProperties.length == 1) {
69+
setValue(metaParam, keyProperties[0], values.get(0));
70+
} else {
71+
MetaObject metaResult = configuration.newMetaObject(values.get(0));
72+
handleMultipleProperties(keyProperties, metaParam, metaResult);
73+
}
6974
}
70-
} else {
71-
throw new ExecutorException("No setter found for the keyProperty '" + keyProperty + "' in " + metaParam.getOriginalObject().getClass().getName() + ".");
7275
}
7376
}
7477
} catch (ExecutorException e) {
@@ -78,4 +81,30 @@ private void processGeneratedKeys(Executor executor, MappedStatement ms, Object
7881
}
7982
}
8083

84+
private void handleMultipleProperties(String[] keyProperties,
85+
MetaObject metaParam, MetaObject metaResult) {
86+
String[] keyColumns = keyStatement.getKeyColumns();
87+
88+
if (keyColumns == null || keyColumns.length == 0) {
89+
// no key columns specified, just use the property names
90+
for (int i = 0; i < keyProperties.length; i++) {
91+
setValue(metaParam, keyProperties[i], metaResult.getValue(keyProperties[i]));
92+
}
93+
} else {
94+
if (keyColumns.length != keyProperties.length) {
95+
throw new ExecutorException("If SelectKey has key columns, the number must match the number of key properties.");
96+
}
97+
for (int i = 0; i < keyProperties.length; i++) {
98+
setValue(metaParam, keyProperties[i], metaResult.getValue(keyColumns[i]));
99+
}
100+
}
101+
}
102+
103+
private void setValue(MetaObject metaParam, String property, Object value) {
104+
if (metaParam.hasSetter(property)) {
105+
metaParam.setValue(property, value);
106+
} else {
107+
throw new ExecutorException("No setter found for the keyProperty '" + property + "' in " + metaParam.getOriginalObject().getClass().getName() + ".");
108+
}
109+
}
81110
}

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
*/
1616
package org.apache.ibatis.submitted.selectkey;
1717

18+
import java.util.Map;
19+
1820
import org.apache.ibatis.annotations.Insert;
1921
import org.apache.ibatis.annotations.InsertProvider;
2022
import org.apache.ibatis.annotations.Options;
@@ -30,6 +32,14 @@ public interface AnnotatedMapper {
3032
@Options(useGeneratedKeys=true, keyProperty="nameId,generatedName", keyColumn="ID,NAME_FRED")
3133
int insertTable2WithOptions(Name name);
3234

35+
@Insert("insert into table2 (name) values(#{name})")
36+
@SelectKey(statement="select id, name_fred from table2 where id = identity()", keyProperty="nameId,generatedName", keyColumn="ID,NAME_FRED", before=false, resultType=Map.class)
37+
int insertTable2WithSelectKeyWithKeyMap(Name name);
38+
39+
@Insert("insert into table2 (name) values(#{name})")
40+
@SelectKey(statement="select id as nameId, name_fred as generatedName from table2 where id = identity()", keyProperty="nameId,generatedName", before=false, resultType=Name.class)
41+
int insertTable2WithSelectKeyWithKeyObject(Name name);
42+
3343
@Insert("insert into table3 (id, name) values(#{nameId}, #{name})")
3444
@SelectKey(statement="call next value for TestSequence", keyProperty="nameId", before=true, resultType=int.class)
3545
int insertTable3(Name name);

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,40 @@ public void testAnnotatedInsertTable2WithOptions() {
169169
}
170170
}
171171

172+
@Test
173+
public void testAnnotatedInsertTable2WithSelectKeyWithKeyMap() {
174+
SqlSession sqlSession = sqlSessionFactory.openSession();
175+
176+
try {
177+
Name name = new Name();
178+
name.setName("barney");
179+
AnnotatedMapper mapper = sqlSession.getMapper(AnnotatedMapper.class);
180+
int rows = mapper.insertTable2WithSelectKeyWithKeyMap(name);
181+
assertEquals(1, rows);
182+
assertEquals(22, name.getNameId());
183+
assertEquals("barney_fred", name.getGeneratedName());
184+
} finally {
185+
sqlSession.close();
186+
}
187+
}
188+
189+
@Test
190+
public void testAnnotatedInsertTable2WithSelectKeyWithKeyObject() {
191+
SqlSession sqlSession = sqlSessionFactory.openSession();
192+
193+
try {
194+
Name name = new Name();
195+
name.setName("barney");
196+
AnnotatedMapper mapper = sqlSession.getMapper(AnnotatedMapper.class);
197+
int rows = mapper.insertTable2WithSelectKeyWithKeyObject(name);
198+
assertEquals(1, rows);
199+
assertEquals(22, name.getNameId());
200+
assertEquals("barney_fred", name.getGeneratedName());
201+
} finally {
202+
sqlSession.close();
203+
}
204+
}
205+
172206
@Test
173207
public void testAnnotatedInsertTable3() {
174208
SqlSession sqlSession = sqlSessionFactory.openSession();

0 commit comments

Comments
 (0)