webentwicklung-frage-antwort-db.com.de

SqlException catch und Behandlung

F: Gibt es eine bessere Möglichkeit, mit SqlExceptions umzugehen? 

In den folgenden Beispielen wird der Text in der Nachricht interpretiert. 

Eg1: Ich habe einen vorhandenen Try-Catch, wenn keine Tabelle vorhanden ist.
Ignoriere die Tatsache, dass ich überhaupt prüfen könnte, ob die Tabelle existiert.

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

Eg2: ohne dass der try catch eine Ausnahme mit einem doppelten Schlüssel zeigt

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

Lösung: Der Start meines 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); }
}
54
Valamas

Die SqlException verfügt über eine Number-Eigenschaft , die Sie überprüfen können. Für doppelte Fehler ist die Nummer 2601.

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

Versuchen Sie Folgendes, um eine Liste aller SQL-Fehler von Ihrem Server abzurufen:

 SELECT * FROM sysmessages

Update

Dies kann jetzt in C # 6.0 vereinfacht werden

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

Art, irgendwie. Siehe Ursache und Lösung von Datenbankmodulfehlern

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: ...
      }
   }
}

Das Problem ist jedoch, dass eine gute DAL-Schicht TRY/CATCHin T-SQL (gespeicherte Prozeduren) verwendet würde, mit einem Muster wie Ausnahmebehandlung und geschachtelten Transaktionen . Leider kann ein TRY/CATCH-T-SQL-Block den ursprünglichen Fehlercode nicht auslösen, er muss einen new -Fehler mit Code über 50000 auslösen. Dies macht die clientseitige Behandlung zu einem Problem. In der nächsten Version von SQL Server gibt es ein neues THROW - Konstrukt, mit dem die ursprüngliche Ausnahme aus T-SQL-Catchblöcken erneut ausgelöst werden kann.

20
Remus Rusanu

Es ist besser, Fehlercodes zu verwenden, Sie müssen nicht analysieren.

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

    }
    else
        throw;
}

So finden Sie heraus, dass 208 verwendet werden sollte:

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

Wenn Sie möchten, dass die Liste der Fehlermeldungen auf dem SQL-Server angezeigt wird, können Sie mit sehen

SELECT *
FROM master.dbo.sysmessages
4
Snake Eyes

Wenn Sie nach einem besseren Weg suchen, mit SQLException umzugehen, gibt es einige Möglichkeiten, die Sie tun könnten. Erstens macht Spring.NET etwas Ähnliches, wonach Sie suchen (denke ich). Hier ist ein Link zu dem, was sie tun:

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

Anstatt die Nachricht anzusehen, können Sie auch den Fehlercode (sqlEx.Number) überprüfen. Dies scheint ein besserer Weg zu sein, um festzustellen, welcher Fehler aufgetreten ist. Das einzige Problem ist, dass die zurückgegebene Fehlernummer für jeden Datenbankanbieter unterschiedlich sein kann. Wenn Sie den Anbieter wechseln möchten, müssen Sie ihn wie gewohnt handhaben oder eine Abstraktionsebene erstellen, die diese Informationen für Sie übersetzt.

Hier ist ein Beispiel eines Mannes, der den Fehlercode und eine Konfigurationsdatei zum Übersetzen und Lokalisieren benutzerfreundlicher Fehlermeldungen verwendet hat:

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

1
IAmTimCorey

Mit MS SQL 2008 können wir unterstützte Fehlermeldungen in der Tabelle sys.messages auflisten

SELECT * FROM sys.messages
1
Thibaut Brard

Für diejenigen, die Anfänger sind, die einen SQL-Fehler auslösen können, wenn Sie von einem anderen Rechner aus eine Verbindung zur DB herstellen (z. B. beim Laden von Formularen), werden Sie feststellen, dass Sie beim ersten Einrichten einer in C # befindlichen Tabelle, die auf eine SQL Server-Datenbank verweist, dies feststellen Es wird eine Verbindung wie folgt aufgebaut:

this.Table_nameTableAdapter.Fill(this.DatabaseNameDataSet.Table_name);

Sie müssen diese Zeile möglicherweise entfernen und durch etwas anderes wie eine herkömmliche Verbindungszeichenfolge ersetzen, wie in MSDN erwähnt usw. 

http://www.connectionstrings.com/sql-server-2008

0
Chris

Ich arbeite zuerst mit Code, C # 7 und Entity Framework 6.0.0.0. Für mich geht das 

Add()
{
     bool isDuplicate = false;
     try
     {
       //add to database 
     }
     catch (DbUpdateException ex)
     {
       if (dbUpdateException.InnerException != null)
       {
          var sqlException = dbUpdateException.InnerException.InnerException as SqlException;
          if(sqlException == null)
             isDuplicate = IsDuplicate(sqlException);
       } 
     }
     catch (SqlException ex)
     {
        isDuplicate = IsDuplicate(ex);
     }  
     if(isDuplicate){
       //handle here
     }
}

bool IsDuplicate(SqlException sqlException)
{
    switch (sqlException.Number)
    {
        case 2627:
            return true;
        default:
            return false;
    }
}

N.B: Meine Abfrage zum Hinzufügen eines Elements zu DB ist in einem anderen Projekt (Layer)

0
reza.cse08

Sie können based nach Schweregrad bewerten. Hinweis: Damit Sie dies verwenden können, müssen Sie OnInfoMessage abonniert haben

conn.InfoMessage += OnInfoMessage;
conn.FireInfoMessageEventOnUserErrors = true;

Ihr OnInfoMessage würde dann Folgendes enthalten:

foreach(SqlError err in e.Errors) {
//Informational Errors
if (Between(Convert.ToInt16(err.Class), 0, 10, true)) {
    logger.Info(err.Message);
//Errors users can correct.
} else if (Between(Convert.ToInt16(err.Class), 11, 16, true)) {
    logger.Error(err.Message);
//Errors SysAdmin can correct.
} else if (Between(Convert.ToInt16(err.Class), 17, 19, true)) {
    logger.Error(err.Message);
//Fatal Errors 20+
} else {
    logger.Fatal(err.Message);
}}

Auf diese Weise können Sie den Schweregrad anstelle der Fehlernummer bewerten und effektiver sein. Weitere Informationen zum Schweregrad hier .

private static bool Between( int num, int lower, int upper, bool inclusive = false )
{
    return inclusive
        ? lower <= num && num <= upper
        : lower < num && num < upper;
}
0
Nim