Quiero volver a generar la misma excepción en SQL Server que acaba de ocurrir en mi bloque try. Puedo lanzar el mismo mensaje pero quiero lanzar el mismo error.
BEGIN TRANSACTION
BEGIN TRY
INSERT INTO Tags.tblDomain (DomainName, SubDomainId, DomainCode, Description)
VALUES(@DomainName, @SubDomainId, @DomainCode, @Description)
COMMIT TRANSACTION
END TRY
BEGIN CATCH
declare @severity int;
declare @state int;
select @severity=error_severity(), @state=error_state();
RAISERROR(@@Error,@ErrorSeverity,@state);
ROLLBACK TRANSACTION
END CATCH
RAISERROR(@@Error, @ErrorSeverity, @state);
Esta línea mostrará un error, pero quiero una funcionalidad como esa. Esto genera un error con el número de error 50000, pero quiero que se arroje el número de error que estoy pasando @@error
,
Quiero capturar este error no en la interfaz.
es decir
catch (SqlException ex)
{
if ex.number==2627
MessageBox.show("Duplicate value cannot be inserted");
}
Quiero esta funcionalidad. que no se puede lograr usando raiseerror
. No quiero dar un mensaje de error personalizado al final.
RAISEERROR
debería devolver el error mencionado a continuación cuando paso ErrorNo para ser arrojado en la captura
Msg 2627, Level 14, State 1, Procedure spOTest_DomainInsert,
Línea 14 Violación de la restricción UNIQUE KEY 'UK_DomainCode'. No se puede insertar una clave duplicada en el objeto 'Tags.tblDomain'. La instrucción se ha terminado.
EDITAR:
¿Cuál puede ser el inconveniente de no usar el bloque try catch si quiero que la excepción se maneje en el frontend considerando que el procedimiento almacenado contiene múltiples consultas que deben ejecutarse?
raiserror
, que es diferente de cómo c # sale después de unthrow
. Así que agregué unreturn
interiorcatch
porque quería igualar ese comportamiento.RAISERROR()
los documentos . La severidad de ≥11 solo salta a unCATCH
bloque si está dentro de unTRY
bloque. Por lo tanto, debe tenerBEGIN TRY…END CATCH
un código alrededor si deseaRAISERROR()
que afecte el control de flujo.SQL 2012 presenta la declaración throw:
http://msdn.microsoft.com/en-us/library/ee677615.aspx
BEGIN TRY BEGIN TRANSACTION ... COMMIT TRANSACTION END TRY BEGIN CATCH ROLLBACK TRANSACTION; THROW END CATCH
fuente
ROLLBACK
línea es importante! Sin él, puede obtener unSQLException: Cannot roll back THROW
.Relanzamiento dentro del bloque CATCH (código anterior a SQL2012, use la declaración THROW para SQL2012 y posterior):
DECLARE @ErrorMessage nvarchar(4000) = ERROR_MESSAGE(), @ErrorNumber int = ERROR_NUMBER(), @ErrorSeverity int = ERROR_SEVERITY(), @ErrorState int = ERROR_STATE(), @ErrorLine int = ERROR_LINE(), @ErrorProcedure nvarchar(200) = ISNULL(ERROR_PROCEDURE(), '-'); SELECT @ErrorMessage = N'Error %d, Level %d, State %d, Procedure %s, Line %d, ' + 'Message: ' + @ErrorMessage; RAISERROR (@ErrorMessage, @ErrorSeverity, 1, @ErrorNumber, @ErrorSeverity, @ErrorState, @ErrorProcedure, @ErrorLine)
fuente
Creo que tus opciones son:
En algún momento, SQL probablemente introducirá un comando reraise o la capacidad de detectar solo ciertos errores. Pero, por ahora, utilice una solución alternativa. Lo siento.
fuente
No puede: solo el motor puede arrojar errores de menos de 50000. Todo lo que puede hacer es lanzar una excepción que se ve así ...
Mira mi respuesta aquí por favor
El interrogador aquí usó transacciones del lado del cliente para hacer lo que quería, lo que creo que es un poco tonto ...
fuente
Ok, esta es una solución ... :-)
DECLARE @Error_Number INT BEGIN TRANSACTION BEGIN TRY INSERT INTO Test(Id, Name) VALUES (newID(),'Ashish') /* Column 'Name' has unique constraint on it*/ END TRY BEGIN CATCH SELECT ERROR_NUMBER() --RAISERROR (@ErrorMessage,@Severity,@State) ROLLBACK TRAN END CATCH
Si observa el bloque de captura, no está generando el error sino que devuelve el número de error real (y también revertiría la transacción). Ahora, en su código .NET, en lugar de detectar la excepción, si usa ExecuteScalar (), obtiene el número de error real que desea y muestra el número apropiado.
Espero que esto ayude,
EDITAR: - Solo una nota, si desea obtener la cantidad de registros afectados e intentar usar ExecuteNonQuery, es posible que la solución anterior no funcione para usted. De lo contrario, creo que se adaptaría a lo que necesita. Házmelo saber.
fuente
La forma de detener la ejecución en un procedimiento almacenado después de que se ha producido un error y devolver el error al programa de llamada es seguir cada declaración que pueda generar un error con este código:
Yo mismo me sorprendí al descubrir que la ejecución en un procedimiento almacenado puede continuar después de un error, sin darme cuenta de que esto puede llevar a algunos errores difíciles de rastrear.
Este tipo de errores de manejo de paralelos (pre .Net) Visual Basic 6. Esperamos el comando Throw en SQL Server 2012.
fuente
Dado que aún no se ha mudado a 2012, una forma de implementar la propagación del código de error original es usar la parte del mensaje de texto de la excepción que está (re) lanzando desde el bloque de captura. Recuerde que puede contener alguna estructura, por ejemplo, texto XML para que el código de la persona que llama lo analice en su bloque de captura.
fuente
También puede crear un procedimiento almacenado contenedor para esos escenarios cuando desee que la instrucción SQL se ejecute dentro de la transacción y alimente el error hasta su código.
CREATE PROCEDURE usp_Execute_SQL_Within_Transaction ( @SQL nvarchar(max) ) AS SET NOCOUNT ON BEGIN TRY BEGIN TRANSACTION EXEC(@SQL) COMMIT TRANSACTION END TRY BEGIN CATCH DECLARE @ErrorMessage nvarchar(max), @ErrorSeverity int, @ErrorState int SELECT @ErrorMessage = N'Error Number: ' + CONVERT(nvarchar(5), ERROR_NUMBER()) + N'. ' + ERROR_MESSAGE() + ' Line ' + CONVERT(nvarchar(5), ERROR_LINE()), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE() ROLLBACK TRANSACTION RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState) END CATCH GO -- Test it EXEC usp_Execute_SQL_Within_Transaction @SQL = 'SELECT 1; SELECT 2' EXEC usp_Execute_SQL_Within_Transaction @SQL = 'SELECT 1/0; SELECT 2' EXEC usp_Execute_SQL_Within_Transaction @SQL = 'EXEC usp_Another_SP'
fuente
Desde el punto de vista del diseño, ¿cuál es el punto de lanzar excepciones con números de error originales y mensajes personalizados? Hasta cierto punto, rompe el contrato de interfaz entre las aplicaciones y la base de datos. Si desea detectar errores originales y manejarlos en un código superior, no los maneje en la base de datos. Luego, cuando detecta una excepción, puede cambiar el mensaje que se le presenta al usuario a lo que desee. Sin embargo, no lo haría, porque hace que el código de su base de datos hmm 'no sea correcto'. Como dijeron otros, debe definir un conjunto de sus propios códigos de error (por encima de 50000) y lanzarlos en su lugar. Luego, puede manejar los problemas de integridad ('No se permiten valores duplicados') por separado de los posibles problemas comerciales: 'El código postal no es válido', 'No se encontraron filas que coincidan con los criterios', etc.
fuente
try { code(); } catch (Exception exc) { log(exc); throw; } finally { cleanup(); }
dondethrow;
solo generará la excepción original, con su contexto original.