如何正确执行以下更新:
using (OracleConnection conn = new OracleConnection())
using (selCmd)
{
string sql1 = "update Table1 set name = joe where id = 10;"
string sql2 = "update Table2 set country = usa where region = americas;"
string sql3 = "update Table3 set weather = sunny where state = CA;"
string sql4 = "update Table4 set engine = v8 where maker = benz;"
cmdUpdate.CommandText = sql(#);
cmdUpdate.Connection = conn;
recs = cmdUpdate.ExecuteNonQuery();
}
如果这是一项交易,我知道全部或全部,但我只是想看看它是如何运作的。
我正在考虑迭代一个项目数组[sql1,sql2,sql3,sql4]并在CommandText中传递sql(#)并每次都执行ExecuteNonQuery。
答案 0 :(得分:9)
如果我没记错的话,可以在一个以分号(;)分隔的字符串中连接多个SQL语句。否则,执行多个ExecuteNonQuery()
调用没有任何问题。
string sql1 = "BEGIN update Table1 set name = 'joe' where id = 10;",
sql2 = "update Table2 set country = 'usa' where region = 'americas';",
sql3 = "update Table3 set weather = 'sunny' where state = 'CA';",
sql4 = "update Table4 set engine = 'v8' where maker = 'benz'; END;";
string sql = string.Format("{0}{1}{2}{3}",sql1,sql2,sql3,sql4);
using (OracleConnection conn = new OracleConnection())
using (OracleCommand cmdUpdate = new OracleCommand(sql, conn))
{
conn.Open();
recs = cmdUpdate.ExecuteNonQuery();
}
答案 1 :(得分:1)
另一种方法是创建一个简单的扩展方法(ExecuteMultipleNonQuery),它只是在所有分号上拆分字符串并在循环中执行每个语句:
public static class DbCommandExtensions {
public static void ExecuteMultipleNonQuery(this IDbCommand dbCommand)
{
var sqlStatementArray = dbCommand.CommandText.Split(new string[] {";"}, StringSplitOptions.RemoveEmptyEntries);
foreach (string sqlStatement in sqlStatementArray)
{
dbCommand.CommandText = sqlStatement;
dbCommand.ExecuteNonQuery();
}
}
}
答案 2 :(得分:0)
我最近在一些旧代码中遇到过这个问题。我们动态构建SQL调用链(支持Oracle和Sql Server)。由于目前没有Oracle生产实施,没有人测试过Oracle操作,客户漏洞也没有进入。我找到了一个构建命令链的代码,然后,对于Oracle,它使用了String.Split(';')
。然后,它使用循环来执行事务中的每个语句:rowsAffecter += ExecuteNonQuery....
我不喜欢这个想法,因为没有参数化它是危险的方法,因为一些数据可以包含;
。但即使参数化已经到位......
...为Oracle("begin... end;"
)进行匿名阻止的问题之一是ExecuteNonQuery
不会返回行数(返回-1),其中有时需要判断某些事情是否得到更新。
解决这个问题我已经完成了这个
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)
之类的东西,它将向集合添加参数并生成:1, :2, :3, etc.
(oracle)和@1, @2, @3, etc.
(sql server),在您的sql语句。