No se puede acceder al objeto SqlTransaction para revertir en el bloque catch


Tengo un problema, y todos los artículos o ejemplos que encontré parecen no importarme.

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 lanzar múltiples excepciones.

Soy ¿está mal, o la mayoría de la gente simplemente ignora este riesgo? ¿Cuál es la mejor solución para poder revertir, si ocurre una excepción?

Author: Marks, 2010-05-26

6 answers

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 podrías ir aún más limpio y más fácil y usar 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;
    }
}
 55
Author: Dave Markle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-20 04:18:19

No me gusta escribir tipos y establecer variables en null, así que:

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 quieres cambiar a MySQL u otro proveedor, solo tienes que modificar 1 línea.

 8
Author: Mike Trusov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-10 05:00:36

Usa esto

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

POR cierto-No lo confirmaste en caso de procesamiento exitoso

 6
Author: Itay Karo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-26 10:39:16
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;
    }
}
 3
Author: Paul Talbot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-26 10:44:00

Microsoft samples, coloque el begin trans fuera del try/catch vea este enlace msdn. Asumo que el método beginTransaction debe lanzar una excepción O comenzar una transacción, pero nunca ambas (aunque la documentación no dice que esto sea imposible).

Sin embargo, usted puede ser mejor de usar TransactionScope que maneja una gran cantidad de la (no tan) carga pesada para usted: este enlace

 1
Author: Daniel Renshaw,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-22 09:11:25
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();
   }
}
 1
Author: Ibki,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-16 05:22:18