2010-05-26 14 views
31

Tengo un problema, y ​​parece que a todos los artículos o ejemplos que encontré no les importa.No se puede acceder al objeto SqlTransaction para deshacer en el bloque catch

Quiero hacer algunas acciones de base de datos en una transacción. Lo que quiero hacer es muy similar a la mayoría de los ejemplos:

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; 
    } 
} 

Pero el problema es que el SqlTransaction Trans se declara dentro del bloque try. Por lo tanto, no es accesible en el bloque catch(). La mayoría de los ejemplos solo hacen Conn.Open() y Conn.BeginTransaction() antes del bloque try, pero creo que es un poco arriesgado, ya que ambos pueden arrojar múltiples excepciones.

¿Estoy equivocado o la mayoría de las personas simplemente ignoran este riesgo? ¿Cuál es la mejor solución para poder retrotraer, si ocurre una excepción?

+2

P.S. ¿Estás seguro de que quieres devolver -1 (un código de error) en lugar de lanzar una excepción? –

Respuesta

55
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 usted podría ir aún más limpio y más fácil y utilizar esto:

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; 
    } 
} 
+0

¿La segunda versión realmente está realizando una reversión cuando se lanza una excepción? Editar: OK, después de leer la documentación que he visto. – Marks

+1

En su primer ejemplo, ¿no necesita especificar que el comando sql está asociado con la transacción? como 'using (SqlCommand Com = new SqlCommand (ComText, Conn, ** trans **))'? ¿O eso es innecesario? ¿Está asociado implícitamente? –

+0

Sí, gracias. Con TransactionScope, no lo hace, pero lo había omitido de mi primer ejemplo. Editado en consecuencia. –

6

uso de este

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 - No lo cometió en caso de tratamiento exitoso

1

muestras de Microsoft, coloque el comienzo de la trans fuera del try/catch see this msdn link. Supongo que el método BeginTransaction arrojaría una excepción O comenzaría una transacción, pero nunca ambas (aunque la documentación no dice que esto es imposible).

Sin embargo, usted puede ser mejor de utilizar TransactionScope que maneja una gran cantidad de la (no tan) trabajo pesado para usted: this link

3
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; 
    } 
} 
+0

Si bien hay más en el código, esto proporciona la mejor granularidad para poder determinar por qué fallaría cada paso. Sin embargo, tenga en cuenta que el SqlCommand debe estar asociado a la transacción. – JWilliams

8

no me gusta escribir tipos y definición de variables a cero, por lo :

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 */ 
} 

Y si quisiera cambiar a MySql u otro proveedor, solo tendría que modificar 1 línea.

0
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(); 
    } 
} 
Cuestiones relacionadas