post icon

Capturar error en SQL Server y volver a Lanzarlo

Cuando trabajamos con SQL Server con aplicaciones clientes escritas en el lenguaje de programación que sea y usamos transacciones controladas con try..catch, podríamos llegar tener problemas si no lo hacemos del modo correcto.

Me explico mejor con un ejemplo práctico, supongamos que tenemos una aplicación de facturación y queremos eliminar una factura, para salvaguardar la integridad de nuestros datos lo más lógico es crear una transacción dentro del procedimiento que hará la baja, así por si ocurre un error en el eliminado del detalle de la factura, no borramos la cabecera, o si ocurre el error al eliminar la cabecera, deshacemos el eliminado previo del detalle para que todo quede como estaba anteriormente. Hasta este punto todo es muy bonito, si en el procedimiento declaramos la transacción controlada por un bloque try y dentro del catch hacemos sólo el rollback, la aplicación nunca se dará por enterada que en la base de datos hubo algún problema, y si éste emite un mensaje de proceso satisfactorio, lo hará incluso cuando tengamos errores. ¿Por qué esto? Simple, la excepción no se expandió desde la base de datos y no pudo ser capturada por la aplicación.

Entonces lo que debemos hacer es agregar un poco de código en el bloque catch que tengamos para expandir y poder avisar al usuario final que algo no funcionó como se esperó.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
USE DB;
GO
BEGIN TRANSACTION;
	BEGIN TRY
		-- Eliminamos el detalle
		DELETE FROM DETALLE_FACTURA WHERE NRO_FACTURA = 999999;
 
		-- Si y solo si se elimino el detalle eliminamos la cabecera
		DELETE FROM FACTURA WHERE NRO_FACTURA = 999999;
 
		-- Confirmamos la transaccion
		COMMIT TRANSACTION;
	END TRY
	BEGIN CATCH
		-- Deshacemos la transaccion
		ROLLBACK TRANSACTION;
 
		-- Variables para capturar el error
		DECLARE @ErrorMensaje NVARCHAR(4000);
		DECLARE @ErrorSeveridad INT;
		DECLARE @ErrorEstado INT;
 
		-- Capturamos el Error
		SELECT @ErrorMensaje = ERROR_MESSAGE(),
			   @ErrorSeveridad = ERROR_SEVERITY(),
			   @ErrorEstado = ERROR_STATE();
 
		-- Usamos RAISERROR dentro del bloque CATCH para expandir
		-- la información del error original y lo lanzamos
		-- para que la aplicacion cliente se entere de lo sucedido
		RAISERROR (@ErrorMensaje, -- El mensaje
		           @ErrorSeveridad, -- La severidad
			   @ErrorEstado -- El estado
		          );
	END CATCH;
GO

Comentarios desde Facebook:

  1. avatar
    chriserc PERU Internet Explorer Windows
    27 agosto 2014 at 17:27 #

    Interesante, gracias

  2. avatar
    Irene NETHERLANDS Mozilla Firefox Windows
    16 febrero 2011 at 17:21 #

    Muy interesante.
    Muchas gracias!

Responder