我有一个客户端 c# 程序正在通过 执行存储过程,包括使用 InfoMessage 事件ExectueNonQuery
捕获和错误输出。PRINT
它工作正常,但我注意到一些奇怪的事情。
当我从 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
当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
vsText
)触发的事件StoredProcedure
:输出:
executenonquery 结果不会在这里执行您想要的操作。但是您仍然可以到达那里,这仅取决于您要将这些信息用于什么目的。
您可以在每次插入“PRINT @@ROWCOUNT”之后添加这一行,并且您应该将受先前操作影响的行数作为输出的一部分(在此处获得“bar”。
或者,您可以将“OUTPUT”参数添加到存储过程以保存结果,然后在运行 executenonquery 时捕获该结果。
编辑:
我设法修改了Jonathan Kehasias放在一起的示例,以包括 statementcompleted 事件处理。只需添加这两行。