В идеале, просто оберните вашу транзакцию оператором «using» или используйте объект TransactionScope, который автоматически откатится, если будет сгенерировано исключение или если транзакция не будет зафиксирована до того, как она выйдет из области видимости.
В остальное время, каким бы уродливым он ни был, я обычно оборачиваю свои откаты в пустой блок try / catch, потому что почти всегда в обработчике catch есть более значимое исключение. Идея состоит в том, что мы хотим выполнить откат, только если сможем, но мы не хотим начинать генерировать новые исключения, если мы не можем (по любым непредсказуемым причинам), потому что транзакция будет откатываться до тех пор, пока она не зафиксирована тем не мение. Вам все еще нужно попытаться очистить его должным образом, чтобы не было необходимости ждать сборщика мусора, но если вы не можете этого сделать, то откат не является настоящей проблемой.
try
{
SqlTransaction trans = connection.BeginTransaction();
///blah blah blah
}
catch(Exception theExceptionICareAbout)
{
try
{
if(trans != null)
{
trans.Rollback();
}
}
catch {}
throw; //re-throws the meaningful exception.
}
Примечание: не передавайте явное исключение повторно (например, «throw theExceptionICareAbout»), потому что это будет воссоздавать трассировку стека. Вместо этого просто используйте команду «throw», которая продолжит стек существующих исключений.