2010-05-26 8 views
31

Mam problem, a wszystkie artykuły i przykłady, które znalazłem, wydają się nie przejmować tym.Nie można uzyskać dostępu do obiektu SqlTransaction w celu wycofania w bloku catch

Chcę wykonać niektóre operacje bazy danych w transakcji. Co chcę zrobić jest bardzo podobna 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 problemem jest to, że SqlTransaction Trans jest zadeklarowana wewnątrz bloku try. Więc nie jest dostępny w bloku catch(). Większość przykładów po prostu robi Conn.Open() i Conn.BeginTransaction() przed blokiem try, ale myślę, że to trochę ryzykowne, ponieważ obie mogą zgłaszać wiele wyjątków.

Czy jestem w błędzie, czy większość ludzi po prostu ignoruje to ryzyko? Jakie jest najlepsze rozwiązanie, aby móc wycofać, jeśli wystąpi wyjątek?

+2

P.S. czy na pewno chcesz zwrócić -1 (kod błędu) zamiast rzucać wyjątek? –

Odpowiedz

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

czy można iść nawet czystsze i łatwiej 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; 
    } 
} 
+0

Czy druga wersja rzeczywiście wykonuje wycofanie po zgłoszeniu wyjątku? Edycja: OK, po przeczytaniu dokumentacji widziałem to. – Marks

+1

W pierwszym przykładzie nie trzeba określać, że polecenie sql jest powiązane z transakcją? takich jak 'using (SqlCommand Com = new SqlCommand (ComText, Conn, ** trans **))'? Czy to jest niepotrzebne? czy jest on pośrednio powiązany? –

+0

Tak, dziękuję. W przypadku transakcji TransactionScope nie, ale pominąłem to z mojego pierwszego przykładu. Edytowane odpowiednio. –

6

użycie 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 dopuściła go w przypadku pomyślnego przetwarzania

1

Próbki Microsoft należy umieścić na początku trans poza try/catch see this msdn link. Zakładam, że metoda BeginTransaction powinna albo wyrzucić wyjątek LUB rozpocząć transakcję, ale nigdy obie (chociaż dokumentacja nie mówi, że to niemożliwe).

jednak może być lepiej korzystania TransactionScope który zarządza wiele (nie zawsze) podnoszenia ciężkich dla Ciebie: 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

Chociaż jest więcej do kodowania, zapewnia to najlepszą ziarnistość, dzięki której można określić, dlaczego każdy krok byłby wadliwy. Należy jednak pamiętać, że SqlCommand musi być powiązana z transakcją. – JWilliams

8

Nie lubię wpisując rodzaje i ustawienie zmiennych do 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ę.

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