RBa*_*ung 9 sql-server ado.net sql-server-2008-r2
我有一个客户端 c# 程序,它通过 执行存储过程ExectueNonQuery
,包括PRINT
使用 InfoMessage 事件捕获和错误输出。它工作正常,但我注意到一些奇怪的事情。
当我从 SSMS 执行存储过程时,它会显示在“消息”选项卡中执行的每个单独 SQL 语句的行数(就好像它来自 InfoMessages)。然而,我的程序从未看到这些消息,尽管它确实捕获了所有相同的其他输出。相反,它只返回 ExecuteNonQuery 函数结果中受影响的行,即所有单个行计数的总和(这是一种无用的)。
例如,这个过程:
use [tempdb]
go
SELECT *
INTO MyCols
FROM sys.columns
go
CREATE PROC foo As
UPDATE MyCols
SET name = name + N''
-- SSMS shows (662 row(s) affected)
UPDATE MyCols
SET name = name + N''
WHERE name like '%x%'
-- SSMS shows (59 row(s) affected)
PRINT 'bar'
-- both SSMS and ExecuteNonQuery get this
-- ExecuteNonQuery returns 721 rows affected
GO
Run Code Online (Sandbox Code Playgroud)
当foo
proc 运行时,SSMS 显示 662 和 59 的行数,但ExecuteNonQuery
只返回 721 的总数。
那么,我怎样才能获得与 SSMS 获得的信息相同的信息呢?
在这里要明确:我对如何更改存储过程以PRINT @@ROWCOUNT
在每个 SQL 语句之后添加s不感兴趣。我知道如何做到这一点,而且由于各种原因,大多数时候这不是一种选择。
我在问如何做 SSMS 在这里所做的事情。在这一点上,我可以随心所欲地更改客户端代码(现在,无论如何),我想做得对。
该SqlCommand.StatementCompleted
事件将在批处理中的每个语句之后触发,并且该事件的一个属性(好吧,几乎是唯一的属性)是受触发该事件的语句影响的行数。
一些注意事项:
SET NOCOUNT ON;
,或者相反,你没有指定SET NOCOUNT OFF;
。Execute___()
,而不是在执行期间触发。StatementCompletedEventArgs.RecordCount
包括从行数SELECT
的语句,而SqlDataReader.RecordsAffected属性只从DML语句(报告行数INSERT
,UPDATE
,DELETE
,等)。StatementCompleted
事件并没有包括从触发事件批次个别SQL语句。但是,事件处理程序sender
作为输入参数发送,这是SqlCommand
查询批次的 ,您可以通过强制转换sender
为SqlCommand
然后查看CommandText
属性来查看该批次(如下面的示例所示)。该文档是非常稀少的这个所以我已经做了一个例子来展示这个事件引发了双方ExecuteNonQuery
和ExecuteScalar
,以及两个特设的查询和存储过程(即SqlCommand.CommandType
的Text
VS StoredProcedure
):
using System;
using System.Data;
using System.Data.SqlClient;
namespace StatementCompletedFiring
{
class Program
{
static void Main(string[] args)
{
using (SqlConnection _Connection =
new SqlConnection("Integrated Security = True;"))
{
using (SqlCommand _Command = new SqlCommand(@"
SET NOCOUNT OFF; -- ensures that the 'StatementCompleted' event fires
EXEC('
CREATE PROCEDURE #TestProc
AS
SELECT * FROM sys.objects;
SELECT * FROM sys.tables;
');
SELECT * FROM sys.objects;
", _Connection))
{
_Command.StatementCompleted += _Command_StatementCompleted;
try
{
_Connection.Open();
_Command.ExecuteNonQuery();
_Command.CommandText = @"
SELECT 123 AS [Bob];
WAITFOR DELAY '00:00:05.000'; --5 second pause to shows when the events fire
SELECT 2 AS [Sally]
UNION ALL
SELECT 5;
";
Console.WriteLine("\n\t");
Console.WriteLine(_Command.ExecuteScalar().ToString());
Console.WriteLine("\n");
_Command.CommandType = CommandType.StoredProcedure;
_Command.CommandText = "#TestProc";
_Command.ExecuteNonQuery();
}
catch (Exception _Exception)
{
throw new Exception(_Exception.Message);
}
}
}
}
static void _Command_StatementCompleted(object sender,
StatementCompletedEventArgs e)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.Write("\nQuery Batch: ");
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine(((SqlCommand)sender).CommandText);
Console.ForegroundColor = ConsoleColor.Red;
Console.Write("Row(s) affected: ");
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine(e.RecordCount.ToString() + "\n");
Console.ResetColor();
}
}
}
Run Code Online (Sandbox Code Playgroud)
输出:
查询批次:
SET NOCOUNT OFF; -- 确保“StatementCompleted”事件触发EXEC(' CREATE PROCEDURE #TestProc AS SELECT * FROM sys.objects;
SELECT * FROM sys.tables; ');
SELECT * FROM sys.objects;
受影响的行数: 453
查询批次:
SELECT 123 AS [Bob];等待延迟 '00:00:05.000'; --5 秒暂停
SELECT 2 AS [Sally] UNION ALL SELECT 5;
受影响的行: 1
查询批次:
SELECT 123 AS [Bob];等待延迟 '00:00:05.000'; --5 秒暂停
SELECT 2 AS [Sally] UNION ALL SELECT 5;
受影响的行: 2
123
查询批次: #TestProc
受影响的行: 453查询批次: #TestProc
受影响的行: 17