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![]()
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
else18
{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![]()
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
else18
{19
builder.Append("\t" + property.ColumnName + " = ? ");20
}22
fldCount ++;23
}24
}25
builder.Append(" WHERE ");26


浙公网安备 33010602011771号