私はこのようにコマンドを実行しています:
var Command = new SqlCommand(cmdText, Connection, tr);
Command.ExecuteNonQuery();
コマンドにはエラーがありますが、.NETはエラーメッセージをスローしません。コマンドが正しく実行されなかったこと、および例外を取得するにはどうすればよいですか?
エラーの重大度が16以上の場合にのみ、C#で例外が発生します。 PRINTを使用している場合、.NETで例外は発生しません。
エラーの発生コードを編集できる場合、これによりC#でSqlExceptionが発生します。
RAISERROR('Some error message', 16, 1)
その後、SqlException.Errorsコレクションの個々のエラーにアクセスできます。
余談ですが、SQL Serverは、直接RAISERROR
を実行しない場合、RETURN
の後にコマンドを実行し続けます。戻らない場合、複数のエラーが返される可能性があります。
.NETは確かにエラーメッセージを表示します...if重大度が16以上(例外をスローするため)-メッセージは例外.Message
。重要度の低いRAISERROR
を使用している場合(またはPRINT
を使用している場合)、接続で InfoMessage
イベント をサブスクライブする必要があります。
重大度の高いエラーのみがExecuteNonQueryでスローされます。 OdbcCommand.ExecuteNonQuery()メソッドで観察した別のシナリオがあります。 SqlCommand.ExecuteNonQuery()についても同様です。 CommandTextプロパティに含まれるSQLが単一のステートメント(例:INSERT INTO table(col1、col2)VALUES(2、 'ABC');)であり、上記のステートメントExecuteNonQueryに外部キー違反または主キー違反がある場合例外をスローします。ただし、CommandTextがセミコロンで区切られた複数のSQLステートメント(複数のINSERTSまたはUPDATESなど)のバッチであり、それらの1つが失敗した場合、ExecuteNonQueryは例外をスローしません。メソッドによって返された、影響を受けるレコードの数を明示的にチェックする必要があります。コードをtry {} Catch {}に置くだけでは効果がありません。
以下をお試しください。
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
このスレッドでのM Hassan、Stefan Steiger、およびMark Gravellの作業に触発されて、ここで行われていることの概念実証の最小限の例を示します。
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);
}
}
これは、Oracle ODP.Netを使用したWCFサービスでうまく機能することがわかりました-
try
{
cmd.Connection = conn;
conn.Open();
cmd.ExecuteNonQuery();
}
catch (OracleException oex)
{
string errmsg = oex.Message;
Logger.Instance.WriteLog(@"Some error --> " + errmsg);
throw new Exception(errmsg);
}
catch (Exception ex)
{
throw ex;
}
finally
{
cleanup...
}