在C#中捕获RAISERROR

时间:2017-07-24 21:52:20

标签: c# sql-server sql-server-2014

我试图找到这个问题的有用答案,但失败了(我发现最接近的是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返回数据的过程。也许答案是“不要这样做”但是很高兴知道在抓取结果时是否有办法简单地捕捉错误。

2 个答案:

答案 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)

我可以提出三点建议:

  1. 使用CommandType.Text代替CommandType.StoredProcedure。这可能现在已经修复,但几年前我发现CommandType.StoredProcedure 总是将消息输出缓冲到大约50个批次中,而CommandType.Text将允许消息来马上回到C#。
  2. WITH NOWAIT代码中添加RAISERROR提示。
  3. 不要忘记FireInfoMessageEventOnUserErrors属性。您确实想要处理InfoMessage事件。
  4. 我不确定其中任何一个会解决你的问题,但他们应该给你一些指导。