【问题标题】:SqlCommand execute with multi resultSqlCommand 执行多个结果
【发布时间】:2016-06-14 02:36:32
【问题描述】:

当我执行 3 行脚本(或更多)时(例如:I UPDATE、II DELETE、III SELECT),SSMS 会给我 3 条消息和 1 条结果:

  1. 我更新 -> x 行受影响
  2. II DELETE-> x 行受影响
  3. III SELECT -> x 行受影响

  4. III SELECT -> 网格视图

我怎样才能让它成为我自己的?使用 C#。

我正在创作:

SqlConnection cn = new SqlConnection("blabla");
SqlCommand cmd = new SqlCommand("my script", cn);

现在我需要执行并获得所有类型的结果

  1. 受影响的行
  2. 受影响的行
  3. 数据表(或数据集)

【问题讨论】:

  • 为什么需要将它们作为 1 个脚本运行?您只需要INSERTUPDATE 和`DELETE` 影响的行数吗?
  • 为什么要在同一个语句中运行它们?使用SqlTransaction,在最后一条语句执行后提交事务。
  • 我需要多合一,因为生成脚本的不是我,有什么办法可以像 Microsoft SQL Server Management Studio 那样做吗?

标签: c# sql-server tsql


【解决方案1】:

如果您订阅 StatementCompleted 事件,您可以获得所需的行数。

var rowCounts = new List<int>();
var resultSets = new List<DataTable>();

using (SqlConnection cn = new SqlConnection(connectionString))
using (SqlCommand cmd = new SqlCommand(myScript, cn))
{
    cmd.StatementCompleted += (sender, eventArgs) =>
    {
        rowCounts.Add(eventArgs.RecordCount);
    };
    cn.Open();

    using (var rd = cmd.ExecuteReader())
    {
        do
        {
            var table = new DataTable();
            table.Load(rd);
            resultSets.Add(table);
        } while (rd.NextResult());
    }
}

//rowCounts now holds all of the reported rowcounts
//resultSets now holds all of the result sets returned.

重要说明,如果有人在他们的脚本中执行了SET NOCOUNT ON,则事件StatementCompleted 将不会触发,要在这种情况下获取行数,您必须在脚本中使用@@rowcount 并将其作为结果集显式返回SELECT.

【讨论】:

    【解决方案2】:

    我假设它使整个事情失败或成功,对吗?为什么不只使用相同的连接和事务,然后在最后提交事务。这就是交易的目的。有关更多示例和详细信息,请参阅SqlTransaction documentation

    private static void Demo1()
    {
        SqlConnection db = new SqlConnection("connstringhere");
        SqlTransaction transaction;
    
        db.Open();
        transaction = db.BeginTransaction();
        try
        {
            var updateResultNums = new SqlCommand("UPDATE", db, transaction).ExecuteNonQuery();
            var deleteResultNums = new SqlCommand("DELETE", db, transaction).ExecuteNonQuery();
            var reader = new SqlCommand("SELECT", db, transaction).ExecuteReader();
            while (reader.Read())
            {
                // read
                // alternatively see http://stackoverflow.com/a/13870892/1260204 if you really want a data table from the SqlCommand
            }
            transaction.Commit();
        }
        catch (SqlException sqlError)
        {
            transaction.Rollback();
            // do something to handle error
        }
        finally
        {
            db.Close(); //close connection
            db.Dispose(); //dispose connection
            transaction.Dispose();
        }
    }
    

    【讨论】:

    • 你真的应该使用using语句并将连接和事务包装在其中,而不是使用catch和finally块。
    • @ScottChamberlain - 我不同意。 using 转换为 IL 中的 try/finally 块,因此,IMO,这取决于某人的个人喜好,因为它对生成的 IL 代码没有任何影响。如果我正在处理的只有 1 个 IDisposable 对象,我喜欢 using 块。如果有很多,那么我讨厌嵌套的外观,如果需要一个 catch 块也是如此。对我来说,使用try/catch/finally 的代码更具可读性,其中所有一次性用品都在finally 中处理。
    • 您不需要嵌套它们,请查看我发布的答案,以获取使用没有缩进嵌套的块的示例。此外,您确实应该按照创建的相反顺序进行处理,transaction 应该在db 之前进行处理。在这种情况下,这无关紧要(我认为),但如果您乱扔垃圾,其他类型可能就不会那么宽容了。
    • @ScottChamberlain - 就解决 OP 问题而言,这是一个很好的答案。这仍然是嵌套,不是吗,嵌套与缩进不同。同样,您更喜欢使用多个 using 块,我的做法是避免它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多