73 votes

Comment attraper une erreur SqlException spécifique ?

Q : Existe-t-il une meilleure façon de gérer les SqlExceptions ?

Les exemples ci-dessous reposent sur l'interprétation du texte du message.

Eg1 : J'ai un try catch existant pour gérer le cas où une table n'existe pas.
Ignorer le fait que je pourrais vérifier si la table existe en premier lieu.

try
{
    //code
}
catch(SqlException sqlEx)
{
        if (sqlEx.Message.StartsWith("Invalid object name"))
        {
            //code
        }
        else
            throw;
}

Eg2 : sans le try catch montrant l'exception de clé dupliquée

if (sqlEx.Message.StartsWith("Cannot insert duplicate key row in object"))

Solution : Le début de mon SqlExceptionHelper

//-- to see list of error messages: select * from sys.messages where language_id = 1033 order by message_id
public static class SqlExceptionHelper
{
    //-- rule: Add error messages in numeric order and prefix the number above the method

    //-- 208: Invalid object name '%.*ls'.
    public static bool IsInvalidObjectName(SqlException sex)
    { return (sex.Number == 208); }

    //-- 2601: Cannot insert duplicate key row in object '%.*ls' with unique index '%.*ls'. The duplicate key value is %ls.
    public static bool IsDuplicateKey(SqlException sex)
    { return (sex.Number == 2601); }
}

156voto

Richard Schneider Points 16054

L'exception SqlException a une Numéro de propriété que vous pouvez vérifier. Pour les erreurs de duplication, le numéro est 2601.

catch (SqlException e)
{
   switch (e.Number)
   {
      case 2601:
         // Do something.
         break;
      default:
         throw;
   }
 }

Pour obtenir une liste de toutes les erreurs SQL de votre serveur, essayez ceci :

 SELECT * FROM sysmessages

Mise à jour

Cela peut maintenant être simplifié en C# 6.0

catch (SqlException e) when (e.Number == 2601)
{
   // Do something.
}

1 votes

Et vous pouvez filtrer par la langue : select * from sysmessages where msglangid=1033. C'est pour l'anglais

0 votes

Bonjour @Richard Schneider Je sais que cette réponse a vieilli, mais je me demandais s'il existait de nouvelles (meilleures) solutions pour créer également le message automatique, puisque j'utilise MVC, et que chaque propriété de modèle a sa propre "traduction". Je suppose que je pourrais écrire un message standard avec le nom de la propriété (parce que je cartographie chaque fois qu'ils sont exactement les mêmes) et ensuite obtenir le nom de la propriété renommée pour afficher le message comme "Il y a déjà un enregistrement connu avec [Value] comme [FieldName] dans notre système, veuillez choisir différemment".

0 votes

Est-ce qu'un catch (Exception e) attraper une exception SQL ? Ou est-il obligatoire d'utiliser catch (SqlException e) ? Parce que d'une manière ou d'une autre catch (Exception e) n'attrape pas "SqlException : Cannot insert duplicate key row".

20voto

Remus Rusanu Points 159382

En quelque sorte, en quelque sorte. Voir Cause et résolution des erreurs du moteur de base de données

class SqllErrorNumbers
{ 
   public const int BadObject = 208;
   public const int DupKey = 2627;
}

try
{
   ...
}
catch(SqlException sex)
{
   foreach(SqlErrorCode err in sex.Errors)
   {
      switch (err.Number)
      {
      case SqlErrorNumber.BadObject:...
      case SqllErrorNumbers.DupKey: ...
      }
   }
}

Le problème, c'est qu'une bonne couche DAL nous permettrait de TRY/CATCH à l'intérieur de le T-SQL (procédures stockées), avec un modèle tel que Traitement des exceptions et transactions imbriquées . Hélas, un T-SQL TRY/CATCH ne peut pas déclencher le code d'erreur original, il devra déclencher un nouveau erreur, avec un code supérieur à 50000. Cela rend la gestion côté client problématique. Dans la prochaine version de SQL Server, il y a une nouvelle fonction LANCER qui permet de lever à nouveau l'exception originale à partir des blocs de capture T-SQL.

11 votes

Merci pour les conseils et les liens. btw : J'aime attraper le sexe :) Je vais commencer à utiliser cela au lieu de sqlEx pour le plaisir. Cela me rappelle les vieux jours classiques de l'asp. On Error Goto Hell

5 votes

Cela ne sonne pas juste, err dans sex.Errors ;)

0 votes

Inside ne gère pas les exceptions de timeout et de transport, donc même avec une gestion parfaite avec une sproc, il est toujours approprié pour l'appel de gérer.

9voto

Alex Aza Points 29204

Il est préférable d'utiliser des codes d'erreur, vous n'avez pas besoin de les analyser.

try
{
}
catch (SqlException exception)
{
    if (exception.Number == 208)
    {

    }
    else
        throw;
}

Comment savoir que 208 doit être utilisé :

select message_id
from sys.messages
where text like 'Invalid object name%'

0 votes

Merci pour les conseils. Je vais créer une aide SqlException. Aussi, merci beaucoup de m'avoir indiqué le tableau sql des erreurs. select * from sys.messages where language_id = 1033

0 votes

Select * from master.dbo.sysmessages where msglangid=1033 ou SELECT * FROM sys.messages WHERE language_id = 1033 pour filtrer uniquement les messages en anglais. De plus, le message_id dans la table système n'est pas une carte univoque comme SqlException.Number. J'ai vérifié sur C# et SQL Server 2008 R2, pour l'erreur Timeout, le SqlException.Number est -2, mais il n'y a pas une telle définition d'erreur dans les tables système.

0 votes

Comment obtenir le language_id ?

4voto

Snake Eyes Points 4537

Si vous voulez la liste des messages d'erreur rencontrés dans le serveur Sql, vous pouvez la voir avec

SELECT *
FROM master.dbo.sysmessages

1voto

BiggsTRC Points 10362

Si vous cherchez une meilleure façon de gérer les SQLException, vous pouvez faire plusieurs choses. Premièrement, Spring.NET fait quelque chose de similaire à ce que vous recherchez (je pense). Voici un lien vers ce qu'ils font :

http://springframework.net/docs/1.2.0/reference/html/dao.html

De même, au lieu de regarder le message, vous pouvez vérifier le code d'erreur ( sqlEx.Number ). Cela semble être un meilleur moyen d'identifier l'erreur qui s'est produite. Le seul problème est que le numéro d'erreur renvoyé peut être différent pour chaque fournisseur de base de données. Si vous envisagez de changer de fournisseur, vous devrez à nouveau gérer la situation comme vous le faites actuellement ou créer une couche d'abstraction qui traduira ces informations pour vous.

Voici l'exemple d'un type qui a utilisé le code d'erreur et un fichier de configuration pour traduire et localiser des messages d'erreur conviviaux :

https://web.archive.org/web/20130731181042/http://weblogs.asp.net/guys/archive/2005/05/20/408142.aspx

0 votes

J'ai utilisé le lien archive.org pour réparer le lien cassé.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X