Как я могу получить сообщение об ошибке, которое происходит при использовании 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);
}
}