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

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

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

Command.ExecuteNonQuery();

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

Ответ 1

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

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

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

Затем вы можете получить каждую отдельную ошибку в коллекции SqlException.Errors.

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

Ответ 2

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

Ответ 3

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

Ответ 4

Вы попадаете в SqlException с помощью try/catch

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

Следующий метод Catch детализирует 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
 -------------------------------------------------------

Ответ 5

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

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

Ответ 6

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

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);
    }
}