1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  package org.apache.ibatis.executor.keygen;
17  
18  import java.sql.Statement;
19  import java.util.List;
20  
21  import org.apache.ibatis.executor.Executor;
22  import org.apache.ibatis.executor.ExecutorException;
23  import org.apache.ibatis.mapping.MappedStatement;
24  import org.apache.ibatis.reflection.MetaObject;
25  import org.apache.ibatis.session.Configuration;
26  import org.apache.ibatis.session.ExecutorType;
27  import org.apache.ibatis.session.RowBounds;
28  
29  
30  
31  
32  
33  public class SelectKeyGenerator implements KeyGenerator {
34  
35    public static final String SELECT_KEY_SUFFIX = "!selectKey";
36    private final boolean executeBefore;
37    private final MappedStatement keyStatement;
38  
39    public SelectKeyGenerator(MappedStatement keyStatement, boolean executeBefore) {
40      this.executeBefore = executeBefore;
41      this.keyStatement = keyStatement;
42    }
43  
44    @Override
45    public void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
46      if (executeBefore) {
47        processGeneratedKeys(executor, ms, parameter);
48      }
49    }
50  
51    @Override
52    public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
53      if (!executeBefore) {
54        processGeneratedKeys(executor, ms, parameter);
55      }
56    }
57  
58    private void processGeneratedKeys(Executor executor, MappedStatement ms, Object parameter) {
59      try {
60        if (parameter != null && keyStatement != null && keyStatement.getKeyProperties() != null) {
61          String[] keyProperties = keyStatement.getKeyProperties();
62          final Configuration configuration = ms.getConfiguration();
63          final MetaObject metaParam = configuration.newMetaObject(parameter);
64          
65          
66          Executor keyExecutor = configuration.newExecutor(executor.getTransaction(), ExecutorType.SIMPLE);
67          List<Object> values = keyExecutor.query(keyStatement, parameter, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
68          if (values.size() == 0) {
69            throw new ExecutorException("SelectKey returned no data.");
70          } else if (values.size() > 1) {
71            throw new ExecutorException("SelectKey returned more than one value.");
72          } else {
73            MetaObject metaResult = configuration.newMetaObject(values.get(0));
74            if (keyProperties.length == 1) {
75              if (metaResult.hasGetter(keyProperties[0])) {
76                setValue(metaParam, keyProperties[0], metaResult.getValue(keyProperties[0]));
77              } else {
78                
79                
80                setValue(metaParam, keyProperties[0], values.get(0));
81              }
82            } else {
83              handleMultipleProperties(keyProperties, metaParam, metaResult);
84            }
85          }
86        }
87      } catch (ExecutorException e) {
88        throw e;
89      } catch (Exception e) {
90        throw new ExecutorException("Error selecting key or setting result to parameter object. Cause: " + e, e);
91      }
92    }
93  
94    private void handleMultipleProperties(String[] keyProperties,
95        MetaObject/../../../org/apache/ibatis/reflection/MetaObject.html#MetaObject">MetaObject metaParam, MetaObject metaResult) {
96      String[] keyColumns = keyStatement.getKeyColumns();
97  
98      if (keyColumns == null || keyColumns.length == 0) {
99        
100       for (String keyProperty : keyProperties) {
101         setValue(metaParam, keyProperty, metaResult.getValue(keyProperty));
102       }
103     } else {
104       if (keyColumns.length != keyProperties.length) {
105         throw new ExecutorException("If SelectKey has key columns, the number must match the number of key properties.");
106       }
107       for (int i = 0; i < keyProperties.length; i++) {
108         setValue(metaParam, keyProperties[i], metaResult.getValue(keyColumns[i]));
109       }
110     }
111   }
112 
113   private void setValue(MetaObject metaParam, String property, Object value) {
114     if (metaParam.hasSetter(property)) {
115       metaParam.setValue(property, value);
116     } else {
117       throw new ExecutorException("No setter found for the keyProperty '" + property + "' in " + metaParam.getOriginalObject().getClass().getName() + ".");
118     }
119   }
120 }