如何从 .NET 捕获 SQL 脚本 运行 的输出,包括受影响的行?

How do you capture the output of a SQL Script run from .NET, including rows affected?

考虑这个简单的 SQL 脚本:

PRINT N'Dropping CREATE_TABLE events from DatabaseLog table...'
DELETE FROM [dbo].[DatabaseLog] WHERE Event = N'CREATE_TABLE'
PRINT N'Dropping ALTER_TABLE events from DatabaseLog table...'
DELETE FROM [dbo].[DatabaseLog] WHERE Event = N'ALTER_TABLE'
PRINT N'Done!'

当来自 SSMS 运行 时,针对 AdventureWorks 2012,它给出了这个输出:

Dropping CREATE_TABLE events from DatabaseLog table...

(70 row(s) affected)
Dropping ALTER_TABLE events from DatabaseLog table...

(117 row(s) affected)
Done!

如何在 .NET 中重现这一点,包括受影响的行?

通过挂接到 SqlConnection 上的 InfoMessage 事件,我得到了 PRINT 语句的输出,但这不包括受影响行的行。理想情况下,我想像 SSMS 中的 运行 一样捕获输出。

注意:脚本是用户提供的,因此修改脚本以手动输出行计数不是一种选择。

ExecuteNonQuery 应该 return 受影响的行;

SqlCommand comm = new SqlCommand("DELETE FROM [dbo].[DatabaseLog] WHERE Event = N'CREATE_TABLE'",conn);
int rowsAffected = comm.ExecuteNonQuery();

终于找到了正确的事件来获取单个语句的计数! StatementCompleted 对单个 SqlCommand 触发多次,每个影响行的语句触发一次。所以:

public static void ExecuteScript(string connectionString, string sql)
{
    using (var conn = new SqlConnection(connectionString))
    {
        conn.InfoMessage += (sender, args) => Console.WriteLine(args.Message);
        conn.FireInfoMessageEventOnUserErrors = true;
        conn.Open();
        using (var cmd = new SqlCommand(sql, conn))
        {
            cmd.StatementCompleted += (sender, args) =>
                Console.WriteLine($"{Environment.NewLine}({args.RecordCount} row(s) affected)");
            cmd.ExecuteNonQuery();
        }
    }
}

重现 SSMS 的输出,针对我迄今为止尝试过的查询,其中包括 CREATE TABLEPRINTINSERTDELETESELECT.

必须将 FireInfoMessageEventOnUserErrors 设置为 true,否则所有 InfoMessage 事件都会出现在末尾,而不是与 StatementCompleted 事件正确交错。但是,当FireInfoMessageEventOnUserErrors设置为true时,如果有错误则不会抛出SqlException,所以必须检查每个InfoMessage是否有错误(如果Class设置为> 10).