我试图找到这个问题的有用答案,但失败了(我发现最接近的是this)。我有一个C#app调用存储过程,它使用SQL TRY/CATCH
来处理错误。我可以使用这样的示例存储过程来复制问题:
if object_id('dbo.TestSQLError') is not null drop proc dbo.TestSQLError
go
create proc dbo.TestSQLError
as
begin try
select 1 / 0
end try
begin catch
raiserror('Bad tings appen mon', 16, 1)
end catch
然后是一个像这样的虚拟程序:
namespace TestSQLError
{
class Program
{
public const string CONNECTION_STRING = @"data source=localhost\koala; initial catalog=test; integrated security=true;";
static void Main(string[] args)
{
try
{
using (SqlConnection conn = new SqlConnection(CONNECTION_STRING))
{
SqlCommand cmd = new SqlCommand("dbo.TestSQLError", conn) { CommandType = System.Data.CommandType.StoredProcedure };
conn.Open();
using (SqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
Console.WriteLine(rdr.GetValue(0).ToString());
}
rdr.Close();
}
conn.Close();
}
Console.WriteLine("Everything looks good...");
}
catch (SqlException se)
{
Console.WriteLine("SQL Error: " + se.Message);
throw se;
}
catch (Exception e)
{
Console.WriteLine("Normal Error: " + e.Message);
throw e;
}
Console.ReadLine();
}
}
}
存储过程会引发16级错误,据我所知,这个错误应该足以造成错误。但是控制永远不会跳到catch块;它就像没有出错一样突然出现。
我读过有人建议使用OUTPUT
参数......我可以这样做,但似乎我必须遗漏一些基本和简单的东西。有人可以帮忙吗?
UPDATE:如果我使用ExecuteNonQuery(),错误传播就好了。但是,我的用例是执行DML并基于该DML返回数据的过程。也许答案是“不要这样做”但是很高兴知道在抓取结果时是否有办法简单地捕捉错误。
答案 0 :(得分:2)
原因是因为引发错误发生在数据读取器中第一个结果集的结尾之后,如果我们在数据读取器上调用NextResult()
,我们只会收到错误!
使用SqlDataReader时,它只会迭代第一个结果 set,在这种情况下将是存储过程中的select
尝试查看更多详情here
using (SqlDataReader rdr = cmd.ExecuteReader())
{
while (!rdr.IsClosed())
{
while (rdr.Read())
{
Console.WriteLine(rdr.GetValue(0).ToString());
}
if (!rdr.NextResult())
{
rdr.Close();
}
}
}
答案 1 :(得分:0)
我可以提出三点建议:
CommandType.Text
代替CommandType.StoredProcedure
。这可能现在已经修复,但几年前我发现CommandType.StoredProcedure
总是将消息输出缓冲到大约50个批次中,而CommandType.Text
将允许消息来马上回到C#。WITH NOWAIT
代码中添加RAISERROR
提示。FireInfoMessageEventOnUserErrors
属性。您确实想要处理InfoMessage
事件。我不确定其中任何一个会解决你的问题,但他们应该给你一些指导。