我最近在一些旧代码中遇到了这个问题。我们动态构建 SQL 调用链(支持 Oracle 和 Sql Server)。由于当前没有 Oracle 生产实施,因此没有人测试 Oracle 操作并且没有出现客户错误。我找到了一个构建命令链的代码,然后,对于它使用的 Oracle String.Split(';')
。然后,它使用循环来执行事务中的每个语句:rowsAffecter += ExecuteNonQuery....
我不喜欢这个想法,因为没有参数化它是危险的方法,因为一些数据可以包含;
. 但即使参数化到位......
...为 Oracle ( )制作匿名块的问题之一是不会返回行数(返回 -1),有时需要判断是否有更新。"begin... end;"
ExecuteNonQuery
为了解决这个问题,我已经这样做了
private string AppendOracleCountOrNothing(StringBuilder sql)
{
if (_myProvider == Providers.Oracle)
sql.AppendLine("rowCnt := rowCnt + SQL%ROWCOUNT;");
}
public void SomeMethod()
{
var longSqlChain = new StringBuilder(2000);
longSqlChain.Append("Insert into table...;");
AppendOracleCountOrNothing(longSqlChain);
if (someCondition)
{
longSqlChain.AppendLine("Update anotherTable...;");
AppendOracleCountOrNothing(longSqlChain);
}
// may be, add some more sql to longSqlChain here....
int rowsAffected;
if (_myProvider == Providers.Oracle)
{
longSqlChain.Insert(0, @"DECLARE
rowCnt number(10) := 0
BEGIN
").AppendLine(@":1 := rowCnt;
END;");
// Now, here we have some abstract wrappers that hide provider specific code.
// But the idea is to prepare provider specific output parameter and then parse its value
IDataParameter p = ParameterWrapper.PrepareParameter(":1", 0, ParameterDirection.Output, myProvider); // note IDataParameter
SqlExecWrapper.ExecuteNonQuery(_myProvider, CommandType.Text, sql, new[]{p});
rowsAffected = p.GetParameterValue(); // GetParameterValue is an extension on IDataParameter
}
else // sql server
{
rowsAffected = SqlExecWrapper.ExecuteNonQuery(_myProvider, CommandType.Text, sql, null);
}
}
这样我们就可以访问 DB 并获取受此调用影响的返回行数。查询也可以参数化。同样,最好开发抽象层,因此,您可以调用类似的东西parameterizer.CreateParameter(10)
,这将在您的 sql 语句中将参数添加到集合并生成:1, :2, :3, etc.
(oracle)和@1, @2, @3, etc.
(sql server)。