7

次の更新を適切に行う方法:

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を実行することを考えています。

4

3 に答える 3

10

私の記憶が正しければ、セミコロン(;)で区切られた1つの文字列に複数の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();
}
于 2012-11-28T00:42:48.387 に答える
2

私は最近、いくつかの古いコードでこの問題に遭遇しました。SQL呼び出しのチェーンを動的に構築します(OracleおよびSQL Serverをサポート)。現在のOracle実稼働実装はないため、Oracleの動作をテストした人は誰もおらず、顧客のバグは発生していません。コマンドのチェーンを構築するコードを見つけ、Oracleの場合はを使用しますString.Split(';')。次に、ループを使用してトランザクション内の各ステートメントを実行します。rowsAffecter += ExecuteNonQuery....

一部のデータにはが含まれる可能性があるため、パラメーター化がないと危険なアプローチになるため、このアイデアは好きではありません;。しかし、パラメータ化が行われている場合でも...

... Oracle()の匿名ブロックを作成する際の問題の1つは、行数を返さない(-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に1回アクセスし、この呼び出しの影響を受ける行の戻り数を取得します。クエリもパラメータ化できます。繰り返しになりますが、抽象化レイヤーを開発する方がよいので、のようなものを呼び出すことができますparameterizer.CreateParameter(10)。これは、コレクションにパラメーターを追加し、SQLステートメントで:1, :2, :3, etc.(oracle)と@1, @2, @3, etc.(sql server)を生成します。

于 2018-04-11T14:42:02.543 に答える
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();
        }
    }

}
于 2014-06-03T11:19:23.423 に答える