iBatis update statement SQL 语句的Bug以及解决办法
iBatis 中可以使用 <generate> 标签自动生成简单的 CRUD SQL 语句,可以节约很多SQL语句的编写工作。但是这个特性有一个小Bug,自动生成的 UPDATE 语句可能存在语法错误。查看一下源代码,发现这确实是 iBatis 的Bug,不过可以通过一个简单的方法避过这个 BUG。
以下是 IBatisNet.DataMapper.Configuration.Statements BuildUpdateQuery 方法的代码片段。
strArray 中保存了那些选择用作 Key 的字段名,因此,后面用判断 if (i < ((count - strArray.Length) - 1)) 来确定是否要在生成的 SET xxx = xxx 后添加逗号。但是,请注意,这个 if 语句的逻辑是错误的,这将导致后面 n(n取决于选择做为Key的字段的数量)个 SET 部分被错误的少添加了逗号。绕过这个BUG的方法很简单,就是将用作Key的那些字段放到 ParameterMap的最后进行声明,这样,少添加的逗号后正好是那些Key字段,也就正好得到了正确的结果。
正确修改的代码,应该是这个样子的(突出显示部分):
以下是 IBatisNet.DataMapper.Configuration.Statements BuildUpdateQuery 方法的代码片段。
1 StringBuilder builder = new StringBuilder();
2 Update update = (Update) statement;
3 int count = statement.ParameterMap.PropertiesList.Count;
4 string[] strArray = update.Generate.By.Split(new char[] { ',' });
5 builder.Append("UPDATE ");
6 builder.Append("\t" + update.Generate.Table + " ");
7 builder.Append("SET ");
8 for (int i = 0; i < count; i++)
9 {
10 ParameterProperty property = statement.ParameterMap.PropertiesList[i];
11 if (update.Generate.By.IndexOf(property.ColumnName) < 0)
12 {
13 if (i < ((count - strArray.Length) - 1))
14 {
15 builder.Append("\t" + property.ColumnName + " = ?,");
16 }
17 else
18 {
19 builder.Append("\t" + property.ColumnName + " = ? ");
20 }
21 }
22 }
23 builder.Append(" WHERE ");
24
2 Update update = (Update) statement;
3 int count = statement.ParameterMap.PropertiesList.Count;
4 string[] strArray = update.Generate.By.Split(new char[] { ',' });
5 builder.Append("UPDATE ");
6 builder.Append("\t" + update.Generate.Table + " ");
7 builder.Append("SET ");
8 for (int i = 0; i < count; i++)
9 {
10 ParameterProperty property = statement.ParameterMap.PropertiesList[i];
11 if (update.Generate.By.IndexOf(property.ColumnName) < 0)
12 {
13 if (i < ((count - strArray.Length) - 1))
14 {
15 builder.Append("\t" + property.ColumnName + " = ?,");
16 }
17 else
18 {
19 builder.Append("\t" + property.ColumnName + " = ? ");
20 }
21 }
22 }
23 builder.Append(" WHERE ");
24
strArray 中保存了那些选择用作 Key 的字段名,因此,后面用判断 if (i < ((count - strArray.Length) - 1)) 来确定是否要在生成的 SET xxx = xxx 后添加逗号。但是,请注意,这个 if 语句的逻辑是错误的,这将导致后面 n(n取决于选择做为Key的字段的数量)个 SET 部分被错误的少添加了逗号。绕过这个BUG的方法很简单,就是将用作Key的那些字段放到 ParameterMap的最后进行声明,这样,少添加的逗号后正好是那些Key字段,也就正好得到了正确的结果。
正确修改的代码,应该是这个样子的(突出显示部分):
1 StringBuilder builder = new StringBuilder();
2 Update update = (Update) statement;
3 int count = statement.ParameterMap.PropertiesList.Count;
4 string[] strArray = update.Generate.By.Split(new char[] { ',' });
5 builder.Append("UPDATE ");
6 builder.Append("\t" + update.Generate.Table + " ");
7 builder.Append("SET ");
8 for (int i = 0, fldCount = 0; i < count; i++)
9 {
10 ParameterProperty property = statement.ParameterMap.PropertiesList[i];
11 if (update.Generate.By.IndexOf(property.ColumnName) < 0)
12 {
13 if (fldCount < ((count - strArray.Length) - 1))
14 {
15 builder.Append("\t" + property.ColumnName + " = ?,");
16 }
17 else
18 {
19 builder.Append("\t" + property.ColumnName + " = ? ");
20 }
22 fldCount ++;
23 }
24 }
25 builder.Append(" WHERE ");
26
2 Update update = (Update) statement;
3 int count = statement.ParameterMap.PropertiesList.Count;
4 string[] strArray = update.Generate.By.Split(new char[] { ',' });
5 builder.Append("UPDATE ");
6 builder.Append("\t" + update.Generate.Table + " ");
7 builder.Append("SET ");
8 for (int i = 0, fldCount = 0; i < count; i++)
9 {
10 ParameterProperty property = statement.ParameterMap.PropertiesList[i];
11 if (update.Generate.By.IndexOf(property.ColumnName) < 0)
12 {
13 if (fldCount < ((count - strArray.Length) - 1))
14 {
15 builder.Append("\t" + property.ColumnName + " = ?,");
16 }
17 else
18 {
19 builder.Append("\t" + property.ColumnName + " = ? ");
20 }
22 fldCount ++;
23 }
24 }
25 builder.Append(" WHERE ");
26