调用存在错误的存储过程,继续并获得完整输出

时间:2017-09-21 10:46:33

标签: c# sql-server stored-procedures error-handling output

我想从C#应用程序调用SQL-Server SP(Integrity Check- Ola Hallengren)。

如果在任何数据库中发现任何损坏(多个),则会抛出错误。

在SSMS中执行PRINT输出包含非常有用的累积输出(与错误消息混合的日志条目)。显然在每个错误之后继续执行。在SSMS中,您可以使用输出到文件来获取包含此内容的文件。

从C#开始,我尝试使用cmd.ExecuteNonQuery(),但它会在第一次出错时中断。

有没有办法从C#调用SP而不打破错误,目标是在最后获得完整的输出?

编辑:

为了测试这个,我找到了一个准备好的损坏的数据库来下载(look here

试试这个

CREATE PROCEDURE dbo.test
AS
BEGIN
    PRINT 'a clean db'
    DBCC CHECKDB (someDb) WITH NO_INFOMSGS;
    PRINT 'a bad db'
    DBCC CHECKDB (SomeCorruptDB) WITH NO_INFOMSGS
    PRINT 'one more clean db'
    DBCC CHECKDB (AotherGoodDB) WITH NO_INFOMSGS
END 
GO
EXEC dbo.test;
GO
DROP PROCEDURE dbo.test;
GO

错误消息来自DBCC CHECKDB 内的。 SP执行到最后一行。

更新

大家好,所有人都有帮助! 对此进行调查。进一步的测试表明,在C#中抛出的SQL-Exception已经包含了所有信息。明显的第一次捕获让我蒙羞。 我发现潜入它,实际上我的SP被执行到最后。 SqlException有一个.Errors属性,可以反映发现的所有错误。 还有很多工作要做,但问题已经解决了。 谢谢你的帮助!

4 个答案:

答案 0 :(得分:2)

PRINT语句结果和其他信息/警告消息需要InfoMessage事件处理程序:

static void test()
{
    try
    {
        var connection = new SqlConnection(connectionString);
        connection.InfoMessage += Connection_InfoMessage;
        var command = new SqlCommand("dbo.test", connection) { CommandType = CommandType.StoredProcedure };
        connection.Open();
        command.ExecuteNonQuery();
    }
    catch (SqlException ex)
    {
        Console.WriteLine(ex.Message);
    }
    Console.ReadLine();
}

private static void Connection_InfoMessage(object sender, SqlInfoMessageEventArgs e)
{
    Console.WriteLine(e.Message);
}

您还可以设置connection.FireInfoMessageEventOnUserErrors = true,以便错误也作为信息消息返回,而不是作为异常引发。这就是SSMS所做的。请注意,由于不会针对这些错误引发SqlException,因此在应用程序代码上有责任以不同于信息错误的方式处理真正的错误。

答案 1 :(得分:2)

如果你想继续,但要详细分析在sql中处理的异常,你需要捕获SQL异常。

<强>已更新

错误抛出程序示例:

create proc ErrorThrower
as
RAISERROR (N'There was a problem', 15, 1);  
RAISERROR (N'There was a 2nd problem', 15, 1); 
GO

一个简单的控制台应用程序,用于建立ADO.NET连接并处理失败:

using System.Data.SqlClient;

static void Main(string[] args)
    {
      var server = ".";
      var database = "tester";

      var connection = $"Server ={server};Database={database};Trusted_Connection=True;";

      var listOfErrors = new List<SqlError>();

      using (SqlConnection cn = new SqlConnection(connection))
      using (SqlCommand cmd = new SqlCommand("exec ErrorThrower", cn))
      {
        cn.Open();

        //handles ONLY SQL Exceptions
        try
        {
          cmd.ExecuteNonQuery();
        }
        catch (SqlException sqlException)
        {
          //Do what you want in your program with the failure of SQL.  I am just echoing it for example purposes, I could log it or do more with it.
          foreach(SqlError error in sqlException.Errors)
          {
             listOfErrors.Add(error);
          }

          Console.WriteLine($"There were {listOfErrors.Count} errors executing");
          listOfErrors.ForEach(x => Console.WriteLine($"\tError was {x.Message}"));
        }

        cn.Close();
      }

      Console.ReadLine();
    }

答案 2 :(得分:1)

cmd.ExecuteNonQuery()的错误是什么? 我不认为这是和#34;抛出相同的错误&#34;在SSMS中。最有可能的另一个原因是SP在C#中断。

据我所知,当一些东西不正确(腐败)时,SP只返回错误(可能是字符串)。多数民众赞成并没有真正抛出错误,因为它只是在您描述它时继续。

答案 3 :(得分:0)

尝试在SQL脚本中识别这些部分,并为每个部分使用try catch,在第一部分中尝试catch,并在每个catch块中收集错误信息,并在第一个try-catch结束后,在SP中的另一个try catch块中开始下一个部分

您可以使用以下代码示例

来尝试此操作
-- First part of your code
BEGIN TRY
  -- your first code part
  PRINT 0 / 0
END TRY
BEGIN CATCH
  -- collect error information
  -- dont thro error jist collect the information to a variable
  PRINT ERROR_MESSAGE()
END CATCH

-- start next part identified part
BEGIN TRY
  -- your first code part
  PRINT
  2
END TRY
BEGIN CATCH
  -- collect error information
  -- dont thro error jist collect the information to a variable
  PRINT ERROR_MESSAGE()
END CATCH