如何在使用ExecuteNonQuery()时收到错误消息?

我正在以这种方式执行命令:

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

在命令中有一个错误,但.NET不会抛出任何错误消息。 我怎么知道命令没有正确执行,以及如何获得exception?

如果您的错误严重性为16或更高,则只能在C#中获得exception。 如果您使用的是PRINT,则不会在.NET中出现exception。

如果您可以编辑raise错误代码,这将导致C#中的SqlException:

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

然后,您可以获取SqlException.Errors集合中的每个错误。

只是注意事项 – 如果之后没有直接RETURN SQL Server将继续在RAISERROR之后运行命令。 如果您不返回,则可能会收到多个错误。

.NET确实会引发错误消息… 如果严重性为16或更高(因为它抛出exception) – 消息将在exception.Message 。 如果您使用较低严重性的RAISERROR (或使用PRINT ),则必须在连接上订阅InfoMessage事件 。

ExecuteNonQuery中只会抛出高严重性错误。 我用OdbcCommand.ExecuteNonQuery()方法观察到另一种情况。 对于SqlCommand.ExecuteNonQuery()也可能是这样。 如果CommandText属性中包含的SQL是单个语句(例如:INSERT INTO表(col1,col2)VALUES(2,’ABC’);)以及上述语句中是否存在外键冲突或主键冲突ExecuteNonQuery会抛出exception。 但是,如果您的CommandText是一个批处理,其中有多个SQL语句由分号分隔(如几个INSERTS或UPDATES),并且如果其中一个失败,则ExecuteNonQuery不会抛出exception。 您需要显式检查方法返回的受影响的记录数。 只需将代码放入try {} Catch {}就不会有帮助。

试试下面的内容。

PS:仅仅因为你使用了一个事务,并不意味着你可以忽略处理exception和回滚。

  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 

您使用try / catch捕获SqlException

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

以下方法捕获可以记录或显示给用户的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 ------------------------------------------------------- 

受到M Hassan,Stefan Steiger和Mark Gravell在这个主题中的工作的启发,这里有一个最小的概念validation示例:

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