ExecuteReader结合InfoMessages事件无返回行时末段消息未触发问题咨询
当结合使用ExecuteReader与InfoMessages事件时,若查询无返回行,末尾的InfoMessages不会被触发;若查询有返回行,则可在最后看到InfoMessages。
无返回行的示例查询:
PRINT 'this is the start of the test' print CHAR(10) + CHAR(13); Select top(0) 1, 2, 3; print CHAR(10) + CHAR(13); print 'this is the end of the test'
上述示例中,最后两行对应的InfoMessages事件未触发,仅当中间查询有返回结果时才会触发。简化后的示例代码如下:
' add handler AddHandler Cmd.Connection.InfoMessage, AddressOf InfoMessageReceived ' execute query reader = Cmd.ExecuteReader While reader.Read() strValue = reader.GetValue(i).ToString() End While ' remove handler RemoveHandler Cmd.Connection.InfoMessage, AddressOf InfoMessageReceived ' consolidate output
请问出现该现象的原因是什么?
这个现象的核心在于SqlDataReader的执行逻辑和SQL Server的消息传输机制:
SQL Server的消息发送机制
SQL Server会将查询中的PRINT输出、警告等信息,和结果集数据分批传输给客户端。当执行SELECT TOP(0)时,它属于空结果集,SQL Server会在发送这个空结果集后直接结束查询响应流,末尾的PRINT语句还没来得及被服务器发送到客户端,连接就已经进入可复用状态。ExecuteReader的资源处理逻辑
调用ExecuteReader获取阅读器后,只有当阅读器完成所有结果集的读取(包括通过NextResult()切换结果集),或者显式关闭/释放阅读器时,.NET才会彻底完成与服务器的交互,触发剩余的InfoMessages。但你的代码中:- 空结果集下
While reader.Read()循环直接跳过,没有调用NextResult()检查后续的消息或结果集 - 阅读器未被显式关闭(或用
Using自动释放),导致.NET提前终止了与服务器的通信,未接收完所有消息
- 空结果集下
有返回行时的差异
当查询有实际返回行时,reader.Read()会逐行读取数据,直到读完所有行。此时.NET会保持与服务器的连接,服务器会继续发送后续的PRINT消息,直到所有结果集和消息传输完毕,最后才触发所有InfoMessages事件。
验证与解决思路
要触发空结果集下的末尾消息,可以在读取完结果后主动调用reader.NextResult(),或用Using语句包裹SqlDataReader确保资源正确释放:
' add handler AddHandler Cmd.Connection.InfoMessage, AddressOf InfoMessageReceived ' execute query using Using to auto-dispose Using reader = Cmd.ExecuteReader While reader.Read() strValue = reader.GetValue(i).ToString() End While ' 主动检查后续结果/消息 While reader.NextResult() End While End Using ' remove handler RemoveHandler Cmd.Connection.InfoMessage, AddressOf InfoMessageReceived
内容的提问来源于stack exchange,提问作者serializer

