Как я могу получить сообщение об ошибке, которое происходит при использовании ExecuteNonQuery ()? - PullRequest
14 голосов
/ 11 августа 2011

Я выполняю команду следующим образом:

var Command = new SqlCommand(cmdText, Connection, tr);

Command.ExecuteNonQuery();

В команде есть ошибка, однако .NET не выдает никакого сообщения об ошибке. Как я мог узнать, что команда не выполнена должным образом, и как получить исключение?

Ответы [ 6 ]

17 голосов
/ 11 августа 2011

.NET действительно выдает сообщение об ошибке ... , если серьезность составляет 16 или выше (так как он вызывает исключение) - сообщение будет в исключении .Message. Если вы используете RAISERROR с более низким уровнем серьезности (или PRINT), вам придется подписаться на событие InfoMessage в соединении .

14 голосов
/ 11 августа 2011

Вы получите исключение только в C #, если серьезность вашей ошибки составляет 16 или выше. Если вы используете PRINT, вы не получите исключение в .NET.

Если вы можете редактировать код ошибки повышения, это приведет к SqlException в C #:

RAISERROR('Some error message', 16, 1)

Затем можно перейти к каждой отдельной ошибке в коллекции SqlException.Errors.

Просто замечание: SQL Server продолжит выполнять команды после RAISERROR, если вы не RETURN сразу после этого. Если вы не вернетесь, вы можете получить несколько ошибок назад.

1 голос
/ 07 февраля 2015

В ExecuteNonQuery будут возвращаться только ошибки высокой степени серьезности.Есть еще один сценарий, который я наблюдал с методом OdbcCommand.ExecuteNonQuery ().Может быть, это верно и для SqlCommand.ExecuteNonQuery ().Если SQL, содержащийся в свойстве CommandText, представляет собой один оператор (Пример: таблица INSERT INTO (col1, col2) VALUES (2, 'ABC');) и если в приведенном выше операторе ExecuteNonQuery имеется нарушение внешнего ключа или нарушения первичного ключавыбросит исключение.Однако, если ваш CommandText представляет собой пакет, в котором у вас есть несколько операторов SQL, разделенных точкой с запятой (например, несколько INSERTS или UPDATES), и если одно из них завершается неудачей, ExecuteNonQuery не возвращает исключение.Вам необходимо явно проверить количество затронутых записей, возвращаемых методом.Простое помещение кода в try {} Catch {} не поможет.

0 голосов
/ 30 января 2018

Вдохновленный работой М. Хасана, Стефана Штайгера и Марка Гравелла в этой теме, здесь приведен минимальный пример подтверждения концепции:

private static void DoSql()
{
    // Errors of severity level of 10 or less 
    // will NOT bubble up to .Net as an Exception to be caught in the usual way
    const string sql = @"RAISERROR('A test error message of low severity', 10, 1)";

    using (SqlConnection conn = new SqlConnection(myConnString))
    {
        conn.Open();

        // Hook up my listener to the connection message generator
        conn.InfoMessage += new SqlInfoMessageEventHandler(MySqlMessageHandler);

        using (SqlCommand cmd = new SqlCommand(sql, conn))
        {
            cmd.ExecuteNonQuery();
            // code happily carries on to this point
            // despite the sql Level 10 error that happened above
        }
    }
}


private static void MySqlMessageHandler(object sender, SqlInfoMessageEventArgs e)
{
    // This gets all the messages generated during the execution of the SQL, 
    // including low-severity error messages.
    foreach (SqlError err in e.Errors)
    {
        // TODO: Something smarter than this for handling the messages
        MessageBox.Show(err.Message);
    }
}
0 голосов
/ 22 июля 2016

Вы получаете SqlException, используя try / catch

 try
  {
       //.......
    Command.ExecuteNonQuery();      
   }
    catch (SqlException ex)
     {   
       log (SqlExceptionMessage(ex).ToString());
     }

Следующий метод Catch details для SqlException, который может быть зарегистрирован или отображен пользователю

  public StringBuilder SqlExceptionMessage(SqlException ex)
    {
        StringBuilder sqlErrorMessages = new StringBuilder("Sql Exception:\n");

        foreach (SqlError error in ex.Errors)
        {
            sqlErrorMessages.AppendFormat("Mesage: {0}\n", error.Message)
                .AppendFormat("Severity level: {0}\n", error.Class)
                .AppendFormat("State: {0}\n", error.State)
                .AppendFormat("Number: {0}\n", error.Number)
                .AppendFormat("Procedure: {0}\n", error.Procedure)
                .AppendFormat("Source: {0}\n", error.Source)
                .AppendFormat("LineNumber: {0}\n", error.LineNumber)
                .AppendFormat("Server: {0}\n", error.Server)
                .AppendLine(new string('-',error.Message.Length+7));

        }
        return sqlErrorMessages;
    }

Сгенерированное сообщение выглядит так:

 Sql Exception:
 Mesage: Error converting data type nvarchar to datetime.
 Severity level: 16
 State: 5
 Number: 8114
 Procedure: Sales by Year
 Source: .Net SqlClient Data Provider
 LineNumber: 0
 Server: myserver
 -------------------------------------------------------
0 голосов
/ 11 августа 2011

Попробуйте ниже.

PS: Если вы используете транзакцию, это не значит, что вы можете пренебречь обработкой исключений и откатов.

 public static void MessageEventHandler( object sender, SqlInfoMessageEventArgs e ) {
         foreach( SqlError error in e.Errors ) {
            Console.WriteLine("problem with sql: "+error);
            throw new Exception("problem with sql: "+error);
         }
      }
      public static int executeSQLUpdate(string database, string command) {
         SqlConnection connection = null;
         SqlCommand sqlcommand = null;
         int rows = -1;
         try {
            connection = getConnection(database);
            connection.InfoMessage += new SqlInfoMessageEventHandler( MessageEventHandler );
            sqlcommand = connection.CreateCommand();
            sqlcommand.CommandText = command;
            connection.Open();
            rows = sqlcommand.ExecuteNonQuery();
          } catch(Exception e) {
            Console.Write("executeSQLUpdate: problem with command:"+command+"e="+e);
            Console.Out.Flush();
            throw new Exception("executeSQLUpdate: problem with command:"+command,e);
         } finally {
            if(connection != null) { connection.Close(); }
         } 
         return rows;
      }

И это правильная обработка транзакций:

//public static void ExecuteInTransaction(Subtext.Scripting.SqlScriptRunner srScriptRunner)
        public override void ExecuteInTransaction(string strSQL)
        {

            System.Data.Odbc.OdbcTransaction trnTransaction = null;

            try
            {


                System.Threading.Monitor.Enter(m_SqlConnection);
                if (isDataBaseConnectionOpen() == false)
                    OpenSQLConnection();

                trnTransaction = m_SqlConnection.BeginTransaction();

                try
                {
                    /*
                    foreach (Subtext.Scripting.Script scThisScript in srScriptRunner.ScriptCollection)
                    {
                        System.Data.Odbc.OdbcCommand cmd = new System.Data.Odbc.OdbcCommand(scThisScript.ScriptText, m_sqlConnection, trnTransaction);
                        cmd.ExecuteNonQuery();
                    }
                    */

                    // pfff, mono C# compiler problem...
                    // System.Data.Odbc.OdbcCommand cmd = new System.Data.Odbc.OdbcCommand(strSQL, m_SqlConnection, trnTransaction);
                    System.Data.Odbc.OdbcCommand cmd = this.m_SqlConnection.CreateCommand();
                    cmd.CommandText = strSQL;

                    cmd.ExecuteNonQuery();

                    trnTransaction.Commit();
                } // End Try
                catch (System.Data.Odbc.OdbcException exSQLerror)
                {
                    Log(strSQL);
                    Log(exSQLerror.Message);
                    Log(exSQLerror.StackTrace);
                    trnTransaction.Rollback();
                } // End Catch
            } // End Try
            catch (Exception ex)
            {
                Log(strSQL);
                Log(ex.Message);
                Log(ex.StackTrace);
            } // End Catch
            finally
            {
                strSQL = null;
                if(m_SqlConnection.State != System.Data.ConnectionState.Closed)
                    m_SqlConnection.Close();
                System.Threading.Monitor.Exit(m_SqlConnection);
            } // End Finally


        } // End Sub ExecuteInTransaction
...