【问题标题】:Capturing RAISERROR in C#在 C# 中捕获 RAISERROR
【发布时间】:2017-07-24 21:52:20
【问题描述】:

我试图找到这个问题的有用答案,但失败了(我找到的最接近的是this)。我有一个 C# 应用程序调用一个存储过程,它使用 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 参数...我可以这样做,但似乎我必须在这里遗漏一些基本和简单的东西。有人可以帮忙吗?

更新:如果我使用 ExecuteNonQuery() 会出现错误传播得很好。但是,我的用例是一个执行 DML 并基于该 DML 返回数据的过程。也许答案是“不要那样做”,但很高兴知道是否有办法在获取结果时简单地捕获错误。

【问题讨论】:

  • 尝试在RAISERROR之后立即添加RETURN语句
  • 它在 TDS 流中的读取可能不如错误消息那么远。没有要处理的结果,因此它可以停止让错误未读。

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


【解决方案1】:

原因是因为 raise 错误发生在数据读取器中的第一个结果集结束之后,我们只有在数据读取器上调用 NextResult() 时才会收到错误!

当使用 SqlDataReader 时,它只会遍历第一个结果 set,在这种情况下将是存储过程中的选择

试试看更多详情here

using (SqlDataReader rdr = cmd.ExecuteReader())
{
    while (!rdr.IsClosed())
    {   
        while (rdr.Read())
        {
            Console.WriteLine(rdr.GetValue(0).ToString());
        }

        if (!rdr.NextResult())
        {
            rdr.Close();
        }
    }
}

【讨论】:

  • 很高兴能帮上忙
【解决方案2】:

我可以提出三个建议:

  1. 使用CommandType.Text 而不是CommandType.StoredProcedure。这现在可能已修复,但几年前我发现CommandType.StoredProcedure总是 将消息输出缓冲成大约 50 个批次,而CommandType.Text 将允许消息返回到 C# 正确离开。
  2. 在您的RAISERROR 代码中添加WITH NOWAIT 提示。
  3. 不要忘记FireInfoMessageEventOnUserErrors 属性。您确实想处理 InfoMessage 事件。

我不确定这些是否能解决您的问题,但它们应该会给您一些指导。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-09
    • 1970-01-01
    • 2012-05-04
    • 1970-01-01
    • 2017-03-10
    • 2013-10-22
    • 1970-01-01
    • 2010-11-01
    相关资源
    最近更新 更多