TransactionScope - Simplificando el trabajo con transacciones.

A partir del Framewrok 2.0 tenemos a nuestra disposición el objeto TransactionScope, que permite simplificar el trabajo con transacciones. Especialmente llamativo es la capacidad de promocionar la transacción a un entorno de transacciones distribuidas (MS DTC - COM+) de forma casi transparente .

Vamos a empezar con un ejemplo sencillito, de esos que no tienen que fallar nunca. Lo primero que debemos hacer es añadir una referencia a System.Transactions en nuestro proyecto.

Sobre una base de datos de prueba, creamos una nueva tabla para nuestro ejemplo.

 

CREATE TABLE

Persona

(CodPersona int IDENTITY,

Nombre varchar(50),

Apellido1 varchar(100),

Apellido2 varchar(100),

FechaNacimiento datetime,

CONSTRAINT PK_Persona PRIMARY KEY (CodPersona)

)

Para acceder a los datos vamos a utilizar LinqToSQL, por lo que añadimos un nuevo archivo de este tipo a nuestro proyecto. Por supuesto también podríamos trabajar con el modelo clásico de ADO.NET. Podemos ver como añadir clases de LinqToSQL a nuestro proyecto desde este enlace:
http://www.devjoker.com/contenidos/Articulos/326/LinQ-To-SQL--Un-ejemplo-sencillo.aspx

Ahora creamos un formulario - con un único botón - y añadimos el siguiente código al evento click del botón.

 

using (TransactionScope transactionScope = new TransactionScope())

{

try

{

AddData();

transactionScope.Complete();

MessageBox.Show("OK");

}

catch (Exception ex)

{

MessageBox.Show(ex.Message,

"Error - Se deshacen los cambios");

}

}

Con esto estamos envolviendo el código con un objeto TransactionScope - que crea a su vez una transacción controlada por el componente de Windows denominado LTM (Lightweight Transaction Coordinator) - es lo que se conoce como ambito o contexto de la transacción.

Posteriormente llamamos a un método que se encarga de grabar los registros en la base de datos y si todo ha ido bien confirmamos las transaccion con el método Complete(). Como vemos todo muy simple.

El método AddData es un simple bucle que inserta 100 registros en la base de datos. Lo vemos - no debemos tener ningún tipo de problema si hemos leido el artículo de LinqToSql que hemos mencionado antes.

 

private void AddData()

{

using (DataDataContext ctx = new DataDataContext())

{

for (int i = 0; i < 100; i++){

Persona p = new Persona();

p.Nombre = String.Format("Nombre {0}", i);

p.Apellido1 = String.Format("Apellido1 {0}", i);

p.Apellido2 = String.Format("Apellido2 {0}", i);

p.FechaNacimiento = DateTime.Now.AddMonths(i * -1);

ctx.Personas.InsertOnSubmit(p);

}

ctx.SubmitChanges();

}

}

Si consultamos los datos de la tabla Persona - que creamos en nuestra base de datos al principio del artículo -tendremos algo así:

CodPersona  Nombre     Apellido1      Apellido2       FechaNacimiento
----------- ---------- -------------- --------------- -----------------------
1           Nombre 0   Apellido1 0    Apellido2 0     2008-07-14 23:26:43.907
2           Nombre 1   Apellido1 1    Apellido2 1     2008-06-14 23:26:43.907
3           Nombre 2   Apellido1 2    Apellido2 2     2008-05-14 23:26:43.907
4           Nombre 3   Apellido1 3    Apellido2 3     2008-04-14 23:26:43.907
5           Nombre 4   Apellido1 4    Apellido2 4     2008-03-14 23:26:43.907
6           Nombre 5   Apellido1 5    Apellido2 5     2008-02-14 23:26:43.907 
...

Todo ha ido bien y no hemos debido tener ningún problema.

Ahora queremos comprobar que cuando las cosas fallan los cambios se deshacen correctamente. Para ello incluimos un nuevo método, que llamará al método de añadir registros (y que acabamos de ver que funciona correctamente) y una finalizada la inserción de datos lanzará un error..

 

private void AddDataWithError()

{

AddData();

throw new ApplicationException("Error provocado");

}

Y modificamos nuestro código para que se llame al método que lanza el error. 

 

using (TransactionScope transactionScope = new TransactionScope())

{

try

{

AddDataWithError();

transactionScope.Complete();

}

catch (Exception ex)

{

MessageBox.Show(ex.Message,

"Error - Se deshacen los cambios");

}

}

Podemos comprobar que la aplicación muestra el mensaje de error y revierte correctamente las inserciones. Para ello insertamos un punto de detención (F9) en la línea que muestra el MessageBox de error. Cuando la ejecución de códgio se pare en el punto de detención, consultamos la base de datos con la siguiente instrucción:

 

SELECT * FROM Persona(NOLOCK)

En este momento podemos observar que se han inserado 100 nuevos registros, pero la transacción aún no ha sido confirmada - por eso debemos especificar NOLOCK para poder ver los datos. Continuamos la ejecución del código y volvemos a lanzar la consulta. La transacción se ha deshecho correctamente y los datos no se ha grabado. Funciona perfectamente.

Pero,¿como se está haciendo commit? ¿ donde se está haciendo el Rollback ? Cuando se crea una transacción utilizando TrasactionScope, se crea una transacción ligera que será controlada por un componente de Windows denominado LTM (Lightweight Transaction Coordinator),  es este componente el encargado de controlar la transacción. Por lo tanto, no es necesario hacer Rollback, una vez que salimos del ambito de la transacción los cambios se deshacen automanticamente si no han sido confirmados. Es decir, cuando salimos de la clausula using que contiene a TransactionScope.

Cuando en la transacción intervienen más de un recursos transaccional (diferentes bases de datos, colas ...) la transacción es promocionada, dejando de ser una transacción ligera - controladas por el LTM - y se convierte en una transacción distribuida - coordinada por el MS DTC (Distributed Transaction Coordinator). Es una técnica realmente potente que abordaremos en posteriores articulos. Como inveniente diremos que el coordinador de transacciones distribuidas en un componente COM+ y que por lo tanto se hace uso de interoperatividad con COM+ (y los problemas que ello puede suponer).

Saludos, DJK

Pedro  Herrarte  Sánchez
TransactionScope - Simplificando el trabajo con transacciones.
Pedro Herrarte Sánchez

Pedro Herrarte, es consultor independiente, ofreciendo servicios de consultoría, análisis, desarrollo y formación. Posee mas de diez años de experiencia trabajando para las principales empresas de España. Es especialista en tecnologías .NET, entornos Web (ASP.NET, ASP.NET MVC,jQuery, HTML5), bases de datos (SQL Server y ORACLE) e integración de sistemas. Es experto en desarrollo (C#, VB.Net, T-SQL, PL/SQL, , ASP, CGI , C, Pro*C, Java, Essbase, Vignette, PowerBuilder y Visual Basic ...) y bases de datos (SQL Server y ORACLE). Pedro es MCP y MAP 2012, es fundador, diseñador y programador de www.devjoker.com..
Fecha de alta:11/08/2008
Última actualizacion:11/08/2008
Visitas totales:24904
Valorar el contenido:
Últimas consultas realizadas en los foros
Últimas preguntas sin contestar en los foros de devjoker.com