Imansible accedere all’object SqlTransaction per eseguire il rollback nel blocco catch

Ho un problema e tutti gli articoli o gli esempi che ho trovato sembrano non interessarsene.

Voglio fare alcune azioni del database in una transazione. Quello che voglio fare è molto simile alla maggior parte degli esempi:

using (SqlConnection Conn = new SqlConnection(_ConnectionString)) { try { Conn.Open(); SqlTransaction Trans = Conn.BeginTransaction(); using (SqlCommand Com = new SqlCommand(ComText, Conn)) { /* DB work */ } } catch (Exception Ex) { Trans.Rollback(); return -1; } } 

Ma il problema è che SqlTransaction Trans è dichiarato all’interno del blocco try . Quindi non è accessibile nel blocco catch() . Molti esempi fanno semplicemente Conn.Open() e Conn.BeginTransaction() prima del blocco try , ma penso che sia un po ‘rischioso, dal momento che entrambi possono lanciare più eccezioni.

Mi sbaglio o la maggior parte delle persone ignora questo rischio? Qual è la soluzione migliore per poter eseguire il rollback, se si verifica un’eccezione?

 using (var Conn = new SqlConnection(_ConnectionString)) { SqlTransaction trans = null; try { Conn.Open(); trans = Conn.BeginTransaction(); using (SqlCommand Com = new SqlCommand(ComText, Conn, trans)) { /* DB work */ } trans.Commit(); } catch (Exception Ex) { if (trans != null) trans.Rollback(); return -1; } } 

o potresti diventare ancora più pulito e facile e usarlo:

 using (var Conn = new SqlConnection(_ConnectionString)) { try { Conn.Open(); using (var ts = new System.Transactions.TransactionScope()) { using (SqlCommand Com = new SqlCommand(ComText, Conn)) { /* DB work */ } ts.Complete(); } } catch (Exception Ex) { return -1; } } 

Non mi piace digitare i tipi e impostare le variabili su null, quindi:

 try { using (var conn = new SqlConnection(/* connection string or whatever */)) { conn.Open(); using (var trans = conn.BeginTransaction()) { try { using (var cmd = conn.CreateCommand()) { cmd.Transaction = trans; /* setup command type, text */ /* execute command */ } trans.Commit(); } catch (Exception ex) { trans.Rollback(); /* log exception and the fact that rollback succeeded */ } } } } catch (Exception ex) { /* log or whatever */ } 

E se volessi passare a MySql o ad un altro provider, dovresti solo modificare 1 riga.

Usa questo

 using (SqlConnection Conn = new SqlConnection(_ConnectionString)) { SqlTransaction Trans = null; try { Conn.Open(); Trans = Conn.BeginTransaction(); using (SqlCommand Com = new SqlCommand(ComText, Conn)) { /* DB work */ } } catch (Exception Ex) { if (Trans != null) Trans.Rollback(); return -1; } } 

BTW – Non l’hai commesso in caso di elaborazione riuscita

 using (SqlConnection Conn = new SqlConnection(_ConnectionString)) { try { Conn.Open(); SqlTransaction Trans = Conn.BeginTransaction(); try { using (SqlCommand Com = new SqlCommand(ComText, Conn)) { /* DB work */ } } catch (Exception TransEx) { Trans.Rollback(); return -1; } } catch (Exception Ex) { return -1; } } 

Campioni Microsoft, posiziona il trans iniziale al di fuori del try / catch vedi questo link msdn . Suppongo che il metodo BeginTransaction debba generare un’eccezione OPPURE iniziare una transazione ma mai entrambe (anche se la documentazione non dice che è imansible).

Tuttavia, potrebbe essere meglio usare TransactionScope che gestisce un sacco di (non così) pesanti operazioni di sollevamento: questo collegamento

 SqlConnection conn = null; SqlTransaction trans = null; try { conn = new SqlConnection(_ConnectionString); conn.Open(); trans = conn.BeginTransaction(); /* * DB WORK */ trans.Commit(); } catch (Exception ex) { if (trans != null) { trans.Rollback(); } return -1; } finally { if (conn != null) { conn.Close(); } }