2009-08-13 13 views
23

He "heredado" un poco el método C# que crea un objeto ADO.NET SqlCommand y bucles sobre una lista de temas que se guarda en la base de datos (SQL Server 2005).Refactoring ADO.NET - SqlTransaction vs TransactionScope

En este momento, se utiliza el enfoque tradicional SqlConnection/SqlCommand, y para asegurarse de que todo funciona, los dos pasos (eliminar entradas antiguas, luego insertar nuevas) se envuelven en una SqlTransaction de ADO.NET.

using (SqlConnection _con = new SqlConnection(_connectionString)) 
{ 
    using (SqlTransaction _tran = _con.BeginTransaction()) 
    { 
     try 
     { 
     SqlCommand _deleteOld = new SqlCommand(......., _con); 
     _deleteOld.Transaction = _tran; 
     _deleteOld.Parameters.AddWithValue("@ID", 5); 

     _con.Open(); 

     _deleteOld.ExecuteNonQuery(); 

     SqlCommand _insertCmd = new SqlCommand(......, _con); 
     _insertCmd.Transaction = _tran; 

     // add parameters to _insertCmd 

     foreach (Item item in listOfItem) 
     { 
      _insertCmd.ExecuteNonQuery(); 
     } 

     _tran.Commit(); 
     _con.Close(); 
     } 
     catch (Exception ex) 
     { 
      // log exception 
      _tran.Rollback(); 
      throw; 
     } 
    } 
} 

Ahora, he estado leyendo mucho sobre la clase de .NET TransactionScope últimamente, y me preguntaba, ¿cuál es el enfoque preferido aquí? Iba a ganar nada (legibilidad, velocidad, fiabilidad) por el cambio a utilizar

using (TransactionScope _scope = new TransactionScope()) 
{ 
    using (SqlConnection _con = new SqlConnection(_connectionString)) 
    { 
    .... 
    } 

    _scope.Complete(); 
} 

Lo que usted prefiere, y por qué?

Marc

Respuesta

14

Usted no va a ganar nada de inmediato al cambiar el código existente para utilizar TransactionScope. Debe usarlo para el desarrollo futuro debido a la flexibilidad que proporciona. En el futuro, será más fácil incluir cosas que no sean llamadas ADO.NET en una transacción.

Por cierto, en su ejemplo publicado, las instancias SqlCommand deben estar en los bloques using.

+0

De acuerdo, gracias John - y sí, tienes razón - este ejemplo no tiene SqlCommand en el uso de() bloques (todavía!) - esto es trabajo en progreso :-) –

+0

re: SQLCommand dentro de usar, ¿hay alguna otra razón, además de la recolección de basura, por ejemplo: Dispose() para un SQLConnection llama al método Close(), ¿así que Dispose() llama a cualquier método SQLCommand? –

+3

Si una clase implementa 'IDisposable', y si crea una instancia de esta clase, debe llamar a Dispose en ella. La forma más sencilla de hacerlo es con un bloque 'using'. Encuentro que es mejor acostumbrarme a implementar uno. –

9

Microsoft recomienda utilizar ámbito de transacción:

http://msdn.microsoft.com/en-us/library/system.transactions.transactionscope.aspx

La idea básica es que ámbito de transacción gestionará el "contexto de transacción ambiente" para usted. Comienza hablando con una base de datos, tiene una transacción SQL, luego habla con la base de datos número 2 y la transacción se eleva a una transacción distribuida.

ámbito de transacción funciona para usted, para que pueda concentrarse en la funcionalidad del sistema, en lugar de la tubería.

EDITAR

Cuando se utiliza un todo ámbito de transacción dentro de ese ámbito está cubierta por la transacción. Por lo tanto, guarde una línea de código, donde conecta el comando a la transacción. Esta es una posible fuente de error, por ejemplo, si hubiera una posibilidad en 1000 de que esta línea hubiera sido olvidada, ¿cuántos se estaría perdiendo?

EDITAR 2

acuerdo con el comentario de Triynko a continuación. Sin embargo, utilizamos Entity Framework, EF cerrará automáticamente y volverá a abrir una conexión para enlistarla en una transacción. No cierra físicamente más la conexión, la libera en el grupo de conexiones y obtiene una nueva, que puede ser la misma o puede ser una diferente.

+0

OK ,. gracias por eso. Pero, ¿me beneficio de alguna manera, si refacto todo (no es solo esta muestra) para usar TransactionScope() en lugar de transacciones integradas ADO.NET? Solo preguntando si el esfuerzo vale la pena, ¿qué gano con eso? –

+8

"Cuando utiliza un alcance de transacción, todo dentro de ese alcance está cubierto por la transacción". No, todo no está cubierto. Solo los comandos emitidos en conexiones enlistadas en el alcance se ven afectados por el alcance. Las conexiones se alistan automáticamente en el alcance si se abren en el alcance; de ​​lo contrario, las conexiones ya abiertas deben alisarse manualmente en el alcance después de su creación llamando a SqlConnection.EnlistTransaction. Si, por ejemplo, abre su conexión y luego crea el alcance de la transacción ... ninguno de sus comandos estará involucrado en la transacción. – Triynko

+0

@Triynko: ¡Su comentario al artículo correspondiente de MSDN es excelente! – abatishchev

6

Solo tenga en cuenta que usando Transaction Scope a veces tendremos muchos problemas porque muchos ajustes que debemos hacer en Server como configurar DTC, Firewall y etc. Así que recomendé usar SqlTransaction es más ahorrar en la implementación.

7

prefiero TransactionScope. No funciona perfectamente en todos los escenarios, pero en el que describes, es la mejor solución.

Mi razonamiento:

  1. alistamiento en la transacción es automática
  2. rollback
  3. transacción en el caso de una excepción es automática

En conjunto, el resultado es un poco menos de código y un general diseño más robusto, ya que el sistema está manejando algunos de los detalles para mí; es una cosa menos que debo recordar hacer.

Además, la inscripción Transaction transparente puede ser particularmente útil cuando tiene una cantidad de métodos anidados en su DAL, aunque debe tener cuidado de no convertir accidentalmente su transacción en una distribución que requiera el DTC. lo que puede suceder si usa múltiples SqlConnections, incluso si apuntan a la misma base de datos.

2

Ok, tal vez es demasiado tarde para esto ... Pero de todos modos, voy a escribirlo para los interesados ​​...

Ya que tengo una idea más clara ahora, después de haber tenido muchas dificultades con mi actual SqlTransaction enfoque basado que podría cambiar a favor de TransactionScope, como lo veo ... principal ventaja de TransactionScope es que se puede utilizar muy fácilmente en la capa de negocio.

2

También tarde ... Puede realizar fácilmente transacciones "anidadas" en la capa empresarial incluso si la base de datos no admite transacciones anidadas. .NET controla el anidamiento y termina usando una transacción de base de datos (al menos en el caso de SQL Server 2008+). Esto hace que sea mucho más fácil reutilizar el código de acceso a datos fuera de su intención original, como parte de una transacción más grande.