web-dev-qa-db-fra.com

comment rediffuser la même exception dans le serveur SQL

Je veux renvoyer la même exception sur le serveur SQL qui s'est produite dans mon bloc try. Je suis capable de lancer le même message mais je veux lancer la même erreur.

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

Cette ligne affichera une erreur, mais je veux une fonctionnalité quelque chose comme ça. Cela soulève une erreur avec le numéro d'erreur 50000, mais je veux qu'un nombre erroné soit généré que je passe @@error,

Je veux capturer cette erreur non à l'interface

c'est à dire.

catch (SqlException ex)
{
if ex.number==2627
MessageBox.show("Duplicate value cannot be inserted");
}

Je veux cette fonctionnalité. qui ne peut pas être atteint en utilisant raiseerror. Je ne veux pas donner un message d'erreur personnalisé à l'arrière.

RAISEERROR devrait renvoyer l'erreur mentionnée ci-dessous lorsque je passe ErrorNo à lancer

Msg 2627, Level 14, State 1, Procedure spOTest_DomainInsert,

Ligne 14 Violation de la contrainte UNIQUE KEY 'UK_DomainCode'. Impossible d'insérer une clé en double dans l'objet 'Tags.tblDomain'. La déclaration a été terminée.

MODIFIER:

Quel peut être l’inconvénient de ne pas utiliser try catch block si je veux que l’exception soit gérée au niveau frontal car la procédure stockée contient plusieurs requêtes à exécuter

68
Shantanu Gupta

Voici un exemple de code propre entièrement fonctionnel permettant d'annuler une série d'instructions si une erreur se produit et de signaler le message d'erreur.

begin try
    begin transaction;

    ...

    commit transaction;
end try
begin catch
    declare @ErrorMessage nvarchar(max), @ErrorSeverity int, @ErrorState int;
    select @ErrorMessage = ERROR_MESSAGE() + ' Line ' + cast(ERROR_LINE() as nvarchar(5)), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE();
    rollback transaction;
    raiserror (@ErrorMessage, @ErrorSeverity, @ErrorState);
end catch
96
Ben Gripka

SQL 2012 introduit l'instruction throw:

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

Si l'instruction THROW est spécifiée sans paramètre, elle doit apparaître à l'intérieur d'un bloc CATCH. Cela provoque l’exception interceptée.

BEGIN TRY
    BEGIN TRANSACTION
    ...
    COMMIT TRANSACTION
END TRY
BEGIN CATCH
    ROLLBACK TRANSACTION;
    THROW
END CATCH
105
Michael

Renvoi à l'intérieur du bloc CATCH (code pré-SQL 2012, utilisez l'instruction THROW pour SQL 2012 et versions ultérieures):

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)
5
nzeemin

Je pense que vos choix sont:

  • Ne pas attraper l'erreur (laissez-la bouillonner)
  • Soulever un personnalisé

À un moment donné, SQL introduira probablement une commande reraise ou la possibilité d’attraper certaines erreurs seulement. Mais pour l'instant, utilisez une solution de contournement. Pardon.

4
Rob Farley

Vous ne pouvez pas: seul le moteur peut générer des erreurs inférieures à 50000. Tout ce que vous pouvez faire est de lever une exception à laquelle ressemble à cela ...

Voir ma réponse ici s'il vous plaît

L’interrogateur a utilisé ici des transactions côté client pour faire ce qu’il voulait, ce qui, à mon avis, est un peu idiot ...

1
gbn

Étant donné que vous n'avez pas encore migré vers 2012, une solution pour implémenter le code d'erreur original consiste à utiliser la partie message texte de l'exception que vous (ré) envoyez du bloc catch. N'oubliez pas qu'il peut contenir une structure, par exemple un texte XML que votre code d'appelant analysera dans son bloc catch.

0
Yuri Makassiouk

Pour arrêter l'exécution dans une procédure stockée après une erreur et remettre l'erreur au programme appelant, suivez chaque instruction susceptible de générer une erreur avec le code suivant:

If @@ERROR > 0
Return

J'ai moi-même été surpris d'apprendre que l'exécution d'une procédure stockée peut continuer après une erreur. Ne pas s'en rendre compte peut rendre difficile la traçabilité des bogues.

Ce type de traitement des erreurs est parallèle (avant .Net) Visual Basic 6. Dans l'attente de la commande Lancer dans SQL Server 2012.

0
Chuck Bevitt

Ok, c'est une solution de contournement ... :-)

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 vous notez le bloc catch, il ne soulève pas l'erreur mais renvoie le numéro d'erreur réel (et annule également la transaction). Désormais, dans votre code .NET, au lieu d'attraper l'exception , Si vous utilisez ExecuteScalar (), vous obtenez le numéro d'erreur réel que vous souhaitez et affichez le numéro approprié.

int errorNumber=(int)command.ExecuteScalar();
if(errorNumber=<SomeNumber>)
{
    MessageBox.Show("Some message");
}

J'espère que cela t'aides,

EDIT: - Juste une note, si vous voulez obtenir le nombre d'enregistrements affectés et essayez d'utiliser ExecuteNonQuery, la solution ci-dessus risque de ne pas fonctionner pour vous. Sinon, je pense que cela conviendrait à ce dont vous avez besoin. Faites le moi savoir.

0
Ashish Gupta

Vous pouvez également créer une procédure stockée wrapper pour les scénarios dans lesquels vous souhaitez que l'instruction SQL soit exécutée dans la transaction et que l'erreur soit renvoyée dans votre code.

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'
0
Sergey