SqlDataReader 和 T-SQL:在使用来自 C# 的“异步”调用时使用“try...catch”和“throw”时不会传播异常

Posted

技术标签:

【中文标题】SqlDataReader 和 T-SQL:在使用来自 C# 的“异步”调用时使用“try...catch”和“throw”时不会传播异常【英文标题】:SqlDataReader and T-SQL: no exception propagated when using 'try...catch' with 'throw' while using an 'Async' call from C# 【发布时间】:2021-10-13 04:27:39 【问题描述】:

我从这样的命令中得到一个数据读取器:

reader = command.ExecuteReaderAsync()

MRE 命令文本:

begin try
    exec('select * from (SELECT 1 as ID) as nnn where ID = ''sdfsdf''') 
end try 
begin catch 
    throw;
end catch

此命令导致 SQL 出错:

将 varchar 值“sdfsdf”转换为数据类型 int 时转换失败

但如果我使用reader.Read(),它不会返回任何结果且不会出错。 在没有任何信息的情况下使事务回滚。

如何获取有关执行阅读器期间发生的错误的信息?

【问题讨论】:

列ID的类型是什么?如果它不是 varchar、text、string... 则无法与字符串进行比较。我在 SQL 方面并没有那么先进,无法按原样理解 from (SELECT 1 as ID),但你在这里比较 if ( (int)1 == (string)"sdfsdf" ) ??? ID 是整数。此比较无效,但通过阅读器执行时不会出错 @.Kye 我还不知道 T-SQL,也不知道与 ADO.NET 的互操作和异常传播,抱歉。也许是某处的环境、旗帜或财产。可能是由于异步:ADO.NET asynchronous methods not throwing exceptions 【参考方案1】:

为了进入您的 TSQL CATCH 块,在您 THROW 捕获的异常之前,exec 的执行完成并向客户端发送一个零行结果集和一个“行计数”。

开启后可以看到改变的顺序

con.FireInfoMessageEventOnUserErrors = true;
con.InfoMessage += (s, a) => Console.WriteLine($"Message: a.Message");

如果你跑了

exec('select * from (SELECT 1 as ID) as nnn where ID = ''sdfsdf''') 

您将在调用 SqlCommand.ExecuteReader() 返回之前看到错误消息。但是使用 CATCH 和 THROW SqlCommand.ExecuteReader() 在收到错误消息之前返回。

您可以像这样捕获错误:

using (var rdr = cmd.ExecuteReader())

    do
    
        while (rdr.Read())
        
            //. . .
        
    
    while (rdr.NextResult());  //this will throw the SqlException

【讨论】:

以上是关于SqlDataReader 和 T-SQL:在使用来自 C# 的“异步”调用时使用“try...catch”和“throw”时不会传播异常的主要内容,如果未能解决你的问题,请参考以下文章

是否需要手动关闭和处置 SqlDataReader?

SqlConnection 和 SqlDataReader 的复用

如何使用 SqlDataReader 返回和使用 IAsyncEnumerable

关于SqlDataReader使用的一点疑惑

如何使用 SqlDataReader 在结构数组中存储多个值

如何在 JavaScript 中使用 C# SQLDataReader 对象