Nie można uzyskać dostępu do obiektu SqlTransaction do wycofywania w bloku catch

Mam problem, i wszystkie artykuły lub przykłady, które znalazłem wydają się nie dbać o to.

Chcę wykonać kilka akcji bazodanowych w transakcji. To, co chcę zrobić, jest bardzo podobne do większości przykładów:

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

Ale problem polega na tym, że SqlTransaction Trans jest zadeklarowana wewnątrz try bloku. Nie jest więc dostępny w bloku catch(). Większość przykładów robi Conn.Open() i Conn.BeginTransaction() przed blokiem try, ale myślę, że to trochę ryzykowne, ponieważ oba mogą rzucać wiele wyjątków.

Am I źle, czy większość ludzi po prostu ignoruje to ryzyko? Jakie jest najlepsze rozwiązanie, aby móc wycofać się w przypadku wystąpienia wyjątku?

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

Albo możesz zrobić jeszcze czystsze i łatwiejsze i użyć tego:

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/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-20 04:18:19

Nie lubię wpisywać typów i ustawiać zmienne NA null, więc:

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

A jeśli chcesz przełączyć się na MySql lub innego dostawcę, musisz zmodyfikować tylko 1 linię.

 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/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-10 05:00:36

Użyj tego

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-Nie zatwierdziłeś go w przypadku pomyślnego przetwarzania

 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/doraprojects.net/template/agent.layouts/content.php on line 54
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/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-26 10:44:00

Microsoft samples, umieść begin trans poza try /catch zobacz ten link msdn . Zakładam, że metoda BeginTransaction powinna albo rzucić wyjątek, albo rozpocząć transakcję, ale nigdy obu (chociaż dokumentacja nie mówi, że jest to niemożliwe).

Jednak może być lepiej używać TransactionScope który zarządza wiele (nie tak) ciężkich podnoszenia dla Ciebie: ten link

 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/doraprojects.net/template/agent.layouts/content.php on line 54
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/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-16 05:22:18