TransactionScope – Simplificando el trabajo con transacciones.

Publicado: septiembre 7, 2010 en Desarrollo TI, SQL
Etiquetas:

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
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().

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

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

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).

Necesita habilitar el acceso DTC a la red como se describe en este artículo Microsoft TechNet. Este cambio puede tener que efectuarse tanto en la base de datos y servidores de aplicaciones. Muchas veces es DTC ya se ha convertido en un servidor de base de datos para que me busque en el servidor de la primera aplicación.

Aquí hay una captura de pantalla de lo que usamos a excepción de “Permitir administración remota”

Pantallazo

comentarios
  1. Daniel Sanchez dice:

    Muchas gracias, me ha sido de gran utilidad.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s