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”时不会传播异常的主要内容,如果未能解决你的问题,请参考以下文章
SqlConnection 和 SqlDataReader 的复用
如何使用 SqlDataReader 返回和使用 IAsyncEnumerable