I have two stored procedures that I want execute wrapped in a transaction. For various reasons, I need to handle the transaction in my application code instead of within the database.
At the moment, my code looks like this:
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)
{
// exception handling and logging code here...
}
When one of the stored procs raises an error, the exception message I am seeing looks like:
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.
Which makes sense, because at the first catch, the transaction has not been rolled back yet.
But I want a "clean" error (without the tran count message - I'm not interested in this because I am rolling 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 procs looks like this:
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()
-- log the error
-- sql logging code here...
raiserror(@ErrMsg, @ErrSeverity, 1)
end catch
UPDATE: I've taken the transaction handling out of my stored procedures and that seems to have solved the problem. Obviously I was doing it wrong - but I'd still like to know how to do it right. Is removing transactions from the stored procedures the best solution?