What is the best way to implement error handling for a SqlTransaction RollBack that already exists within a catch clause? My code is roughly like this:
using (SqlConnection objSqlConn = new SqlConnection(connStr)) {
objSqlConn.Open();
using (SqlTransaction objSqlTrans = objSqlConn.BeginTransaction()) {
try {
// code
// more code
// and more code
}
catch (Exception ex) {
// What happens if RollBack() has an exception?
objSqlTrans.Rollback();
throw ex;
}
}
}
I believe that my application had an exception in the try block, which in turn was caught in the catch block and then the RollBack was attempted. However, the error that I'm seeing says something about a SqlTransaction.ZombieCheck(), which is making me wonder if the RollBack() itself threw an exception as well. So, do I need to implement some type of error handling at the RollBack()? How do I do that and manage to hold on to the exception that put the execution into the catch block in the first place?
EDIT - All of my code:
using (SqlConnection objSqlConn = new SqlConnection(connStr)) {
objSqlConn.Open();
// Begin Transaction
using (SqlTransaction objSqlTrans = objSqlConn.BeginTransaction()) {
try {
// Create file in db (which in turn creates it on disk according to where the
// ...FileStream points)
SqlCommand objSqlCmd = new SqlCommand("usp_FileAdd", objSqlConn, objSqlTrans);
objSqlCmd.CommandType = CommandType.StoredProcedure;
// Sql parameter - report name
SqlParameter objSqlParam1 = new SqlParameter("@ObjectID", SqlDbType.Int);
objSqlParam1.Value = objID;
// Sql out parameter - returns the file path
SqlParameter objSqlParamOutput = new SqlParameter("@filepath", SqlDbType.VarChar, -1);
objSqlParamOutput.Direction = ParameterDirection.Output;
// Add Sql parameters to command obj
objSqlCmd.Parameters.Add(objSqlParam1);
objSqlCmd.Parameters.Add(objSqlParamOutput);
// Execute command object
objSqlCmd.ExecuteNonQuery();
// Path to the FileStream
string path = objSqlCmd.Parameters["@filepath"].Value.ToString();
// Reset command object to get FileStream
objSqlCmd = new SqlCommand(
"SELECT GET_FILESTREAM_TRANSACTION_CONTEXT()",
objSqlConn,
objSqlTrans);
// Execute command object
Object obj = objSqlCmd.ExecuteScalar();
if (obj != DBNull.Value) {
// Byte array representing the FileStream
byte[] fsBytes = (byte[])obj;
SqlFileStream sqlFS = new SqlFileStream(path, fsBytes, FileAccess.Write);
using (FileStream fs = fi.OpenRead()) {
//byte[] b = new byte[1024];
byte[] b = new byte[4096];
int read;
fs.Seek(0, SeekOrigin.Begin);
while ((read = fs.Read(b, 0, b.Length)) > 0) {
sqlFS.Write(b, 0, read);
}
}
sqlFS.Close();
}
// Commit the transaction
objSqlTrans.Commit();
}
catch (Exception ex) {
objSqlTrans.Rollback();
throw ex;
}
}
}