2009-11-04 8 views
26

Il titolo è davvero la domanda per questo: Esiste un equivalente in "lancio" di T-SQL a C#? rilanciare le eccezioni?Esiste un equivalente in "lancio" di T-SQL a C#? rilanciare le eccezioni?

In C# si può fare questo:

try 
{ 
    DoSomethingThatMightThrowAnException(); 
} 
catch (Exception ex) 
{ 
    // Do something with the exception 
    throw; // Re-throw it as-is. 
} 

C'è qualcosa in termini di funzionalità di T-SQL BEGIN CATCH che fa lo stesso?

risposta

33

È possibile utilizzare RAISERROR. Dal MSDN documentation su RAISERROR:

BEGIN TRY 
    -- RAISERROR with severity 11-19 will cause execution to 
    -- jump to the CATCH block 
    RAISERROR ('Error raised in TRY block.', -- Message text. 
       16, -- Severity. 
       1 -- State. 
       ); 
END TRY 
BEGIN CATCH 
    DECLARE @ErrorMessage NVARCHAR(4000); 
    DECLARE @ErrorSeverity INT; 
    DECLARE @ErrorState INT; 

    SELECT @ErrorMessage = ERROR_MESSAGE(), 
      @ErrorSeverity = ERROR_SEVERITY(), 
      @ErrorState = ERROR_STATE(); 

    -- Use RAISERROR inside the CATCH block to return 
    -- error information about the original error that 
    -- caused execution to jump to the CATCH block. 
    RAISERROR (@ErrorMessage, -- Message text. 
       @ErrorSeverity, -- Severity. 
       @ErrorState -- State. 
       ); 
END CATCH; 

EDIT:

Questo non è proprio la stessa cosa di 's throw o throw ex C#. Come @henrikstaunpoulsen indica che non si ottiene il numero di errore originale nel nuovo errore (RAISERROR è limitato in quali numeri può essere utilizzato). Dovresti usare una sorta di convenzione e analizzare le informazioni (se disponibili) dal messaggio.

MSDN ha un articolo Using TRY...CATCH in Transact-SQL e ho usato un po 'di codice per creare il test di seguito:

use test; 
GO 

IF OBJECT_ID (N'usp_RethrowError',N'P') IS NOT NULL 
    DROP PROCEDURE usp_RethrowError; 
GO 

CREATE PROCEDURE usp_RethrowError AS 
    IF ERROR_NUMBER() IS NULL 
     RETURN; 

    DECLARE 
     @ErrorMessage NVARCHAR(4000), 
     @ErrorNumber  INT, 
     @ErrorSeverity INT, 
     @ErrorState  INT, 
     @ErrorLine  INT, 
     @ErrorProcedure NVARCHAR(200); 

    SELECT 
     @ErrorNumber = ERROR_NUMBER(), 
     @ErrorSeverity = ERROR_SEVERITY(), 
     @ErrorState = ERROR_STATE(), 
     @ErrorLine = ERROR_LINE(), 
     @ErrorProcedure = ISNULL(ERROR_PROCEDURE(), '-'); 

    SELECT @ErrorMessage = 
     N'Error %d, Level %d, State %d, Procedure %s, Line %d, ' + 
      'Message: '+ ERROR_MESSAGE(); 

    RAISERROR 
     (
     @ErrorMessage, 
     @ErrorSeverity, 
     @ErrorState,    
     @ErrorNumber, -- parameter: original error number. 
     @ErrorSeverity, -- parameter: original error severity. 
     @ErrorState,  -- parameter: original error state. 
     @ErrorProcedure, -- parameter: original error procedure name. 
     @ErrorLine  -- parameter: original error line number. 
     ); 
GO 

PRINT 'No Catch' 
DROP TABLE XXXX 

PRINT 'Single Catch' 
BEGIN TRY 
    DROP TABLE XXXX 
END TRY 
BEGIN CATCH 
    EXEC usp_RethrowError; 
END CATCH; 

PRINT 'Double Catch' 
BEGIN TRY 
    BEGIN TRY 
     DROP TABLE XXXX 
    END TRY 
    BEGIN CATCH 
     EXEC usp_RethrowError; 
    END CATCH; 
END TRY 
BEGIN CATCH 
    EXEC usp_RethrowError; 
END CATCH; 

che produce il seguente output:

No Catch 
Msg 3701, Level 11, State 5, Line 3 
Cannot drop the table 'XXXX', because it does not exist or you do not have permission. 
Single Catch 
Msg 50000, Level 11, State 5, Procedure usp_RethrowError, Line 25 
Error 3701, Level 11, State 5, Procedure -, Line 7, Message: Cannot drop the table 'XXXX', because it does not exist or you do not have permission. 
Double Catch 
Msg 50000, Level 11, State 5, Procedure usp_RethrowError, Line 25 
Error 50000, Level 11, State 5, Procedure usp_RethrowError, Line 25, Message: Error 3701, Level 11, State 5, Procedure -, Line 16, Message: Cannot drop the table 'XXXX', because it does not exist or you do not have permission. 
+1

Non c'è un problema con questo, in quanto il numero di errore è diverso dall'eccezione originale? –

+0

@henrikstaunpoulsen Sì, hai ragione. Non penso che sia possibile in T-SQL o in qualsiasi altro modo. Ho aggiornato il post con ulteriori informazioni su questo punto. – ongle

+0

in sql 2012 c'è la nuova parola chiave THROW – sergiom

0

Io generalmente utilizzare il seguente:

DECLARE @Outcome as bit 
DECLARE @Error as int 

BEGIN TRANSACTION 

-- *** YOUR TSQL TRY CODE HERE **** 


-- Capture the TSQL outcome. 
SET @Error = @@ERROR 

-- Set the Outcome to be returned to the .NET code to successful 
SET @Outcome = 1 


IF @Error <> 0 
    BEGIN 
     -- An Error was generate so we invoke ROLLBACK 
     ROLLBACK 
     -- We set the Outcome to be returned to .Net to unsuccessful 
     SET @Outcome = 0 
    end 

ELSE 
    BEGIN 
     -- The transaction was successful, invoke COMMIT 
     COMMIT 
    END 



-- Returning a boolean value to the .NET code 
Select @Outcome as Outcome 
+0

Se si controlla solo @@ ERRORE una volta, non si rileverà solo un errore nell'ultima istruzione del proprio codice SQL? Per esempio. 'SELEZIONA 1/0; SELEZIONA 1; SELECT @@ ERROR' restituisce un errore di 0. L'uso di @@ ERROR sembra peggiore rispetto all'utilizzo dei blocchi TRY CATCH. – Jim

2

Ecco quello che ho usato per rigenerare un'eccezione dopo il rollback della transazione. Ciò fornisce anche le informazioni sul numero di riga dell'errore.

BEGIN TRY 
    BEGIN TRANSACTION -- Start the transaction 

    -- Do your work here 

    -- Commit the transaction 
    COMMIT TRANSACTION 

END TRY 

BEGIN CATCH 
    -- There was an error, rollback the transaction 
    IF @@TRANCOUNT > 0 
     ROLLBACK TRANSACTION 

    -- Raise an error with the details of the exception 
    DECLARE @ErrorMessage nvarchar(2048) 
    DECLARE @ErrorProcedure nvarchar(128) 
    DECLARE @ErrorState int 
    DECLARE @ErrorLine int 
    DECLARE @ErrorSeverity int 

    SET @ErrorProcedure = ERROR_PROCEDURE() 
    SET @ErrorLine = ERROR_LINE() 
    SET @ErrorSeverity = ERROR_SEVERITY() 
    SET @ErrorState = ERROR_STATE() 
    SET @ErrorMessage = '' 

    IF @ErrorProcedure IS NOT NULL 
     SET @ErrorMessage = @ErrorMessage + @ErrorProcedure + ' '; 

    IF @ErrorLine IS NOT NULL 
     SET @ErrorMessage = @ErrorMessage + '[Line ' + CAST(@ErrorLine as nvarchar) + '] '; 

    SET @ErrorMessage = @ErrorMessage + ERROR_MESSAGE() 

    RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState) 
END CATCH 
2

Al fine di prevenire il ripetersi di numeri informazioni/error/linea procedura in molteplici scenari di cattura, io uso una procedura simile, con la piccola modifica nel modo seguente:

IF @Error_Procedure <> OBJECT_NAME(@@PROCID)  
    BEGIN 
     RAISERROR('[Procedure: %s]: Nest Level: %d; Line: %d; Error Number: %d; Message: %s',@Error_Severity,@Error_State,@Error_Procedure, @NestLevel, @Error_Line, @Error_Number, @Error_Message) 
    END 
ELSE 
    BEGIN 
     RAISERROR(@Error_Message,@Error_Severity,@Error_State) 
    END 

Quindi, se abbiamo già catturato e ri-alzato l'errore con questo SP, non aggiungiamo ripetutamente le informazioni aggiuntive, quindi in ambito esterno, vediamo solo l'errore come originariamente controrilanciato.

Negli esempi sopra riportati, l'uscita a doppia cattura sarebbe la stessa dell'uscita a cattura singola. Includo anche il livello del nido nel messaggio di errore per facilitare il debug.

14

In SQL 2012 hanno aggiunto la parola chiave new LANCIO, che possono essere utilizzati anche per ri-generare un'eccezione

USE tempdb; 
GO 
CREATE TABLE dbo.TestRethrow 
( ID INT PRIMARY KEY 
); 
BEGIN TRY 
    INSERT dbo.TestRethrow(ID) VALUES(1); 
-- Force error 2627, Violation of PRIMARY KEY constraint to be raised. 
    INSERT dbo.TestRethrow(ID) VALUES(1); 
END TRY 
BEGIN CATCH 

    PRINT 'In catch block.'; 
    THROW; 
END CATCH; 

http://msdn.microsoft.com/en-us/library/ee677615.aspx

Problemi correlati