I have two stored procedures that I want to execute wrapped in a transaction. For various reasons, I need to process the transaction in the application code, and not in the database.
At the moment, my code is as follows:
try { using (SqlConnection conn = Connection()) { conn.Open(); using (SqlTransaction sqlTrans = conn.BeginTransaction()) { try { using (SqlCommand cmd1 = new SqlCommand("Stored_Proc_1", conn, sqlTrans)) { cmd1.CommandType = CommandType.StoredProcedure; cmd1.ExecuteNonQuery(); } using (SqlCommand cmd2 = new SqlCommand("Stored_Proc_2", conn, sqlTrans)) { cmd2.CommandType = CommandType.StoredProcedure; cmd2.ExecuteNonQuery(); } sqlTrans.Commit(); } catch { sqlTrans.Rollback(); throw; } } conn.Close(); } } catch (SqlException ex) {
When one of the stored procs throws an error, the exception message that I see looks like this:
Error message from raiserror within stored procedure. Transaction count after EXECUTE indicates that a COMMIT or ROLLBACK TRANSACTION statement is missing. Previous count = 1, current count = 0.
This makes sense, because at the first catch, the transaction is not yet rollback.
But I want a βcleanβ error (without a tran count message - this does not interest me because I roll back the transaction) for my exception handling code. Is there a way I can restructure my code to achieve this?
EDIT:
The basic structure of my stored processes is as follows:
create proc Stored_Proc_1 as set nocount on begin try begin transaction raiserror('Error raised by Stored_Proc_1', 16, 1) commit end try begin catch if (@@trancount > 0) rollback declare @ErrMsg nvarchar(4000), @ErrSeverity int, @ErrProc sysname, @ErrLine varchar(10) select @ErrMsg = ERROR_MESSAGE(), @ErrSeverity = ERROR_SEVERITY(), @ErrProc = ERROR_PROCEDURE(), @ErrLine = ERROR_LINE()
UPDATE: I took transaction processing from my stored procedures and seems to have solved the problem. Obviously, I did it wrong, but I still would like to know how to do it right. Does a transaction remove the best solution from stored procedures?