2013-03-22 65 views
6

Ich rufe eine gespeicherte Prozedur auf, die Daten in eine SQL Server-Datenbank von C# einfügt. Ich habe eine Reihe von Beschränkungen auf dem Tisch wie eindeutige Spalt etc. Derzeit habe ich den folgenden Code:beste Möglichkeit, Datenbankeinschränkungsfehler zu fangen

try 
{ 
    // inset data 
} 
catch (SqlException ex) 
{ 
    if (ex.Message.ToLower().Contains("duplicate key")) 
    { 

     if (ex.Message.ToLower().Contains("url")) 
     { 
      return 1; 
     } 

     if (ex.Message.ToLower().Contains("email")) 
     { 
      return 2; 
     } 
    } 

    return 3; 
} 

Ist es besser Praxis zu überprüfen, ob Spalte eindeutig etc ist, bevor die Daten in C# Einfügen oder in Speicherprozedur oder eine Ausnahme auftreten und wie oben behandeln? Ich bin kein Fan der oben genannten, aber auf der Suche nach Best Practice in diesem Bereich.

+0

Als Neben, wenn Sie dies überprüfen. Ich würde nach dem ErrorCode suchen, da dieser eindeutiger und weniger wahrscheinlich zu ändern ist: http://msdn.microsoft.com/en-us/library/aa258747(v=sql.80).aspx –

Antwort

6

Ich sehe Datenbank Einschränkungen als letztes Mittel Art von Sache. (Das heißt, sie sollten in Ihrem Schema als Backup-Methode zur Aufrechterhaltung der Datenintegrität vorhanden sein.) Aber ich würde sagen, dass die Daten wirklich gültig sein sollten vor Sie versuchen, es in der Datenbank zu speichern. Wenn aus einem anderen Grund eine Rückmeldung über eine ungültige Eingabe ein UI-Problem darstellt und ein Datengültigkeitsfehler wirklich nicht jedes Mal den gesamten Ebenenstapel auf und ab blubbern sollte.

Darüber hinaus gibt es viele Arten von Zusicherungen, die Sie über die Form Ihrer Daten machen möchten, die nicht einfach mit Einschränkungen ausgedrückt werden können. (Z. B. Statusübergänge einer Bestellung. "Eine Bestellung kann nur von SHIPPED aus PAID" oder komplexeren Szenarien gehen.) Das bedeutet, dass Sie prozedursprachliche Überprüfungen verwenden müssen, die noch mehr Ihrer Geschäftslogik verdoppeln und dann müssen diese auch eine Art Fehlercode melden und noch mehr Komplexität in Ihre App einbeziehen, nur um all Ihre Daten in der Schemadefinition zu validieren.

Validierung ist von Natur aus schwer in einer App zu platzieren, da es sich sowohl die UI und ist mit dem Modellschema gekoppelt, aber ich veer auf der Seite der es in der Nähe des UI zu tun.

+1

stimme ich vollständig zu. Ein Einschränkungsfehler weist auf einen Fehler in Ihrem Code hin - Ihr Code erlaubte dem Benutzer, Daten einzugeben, die die Datenbank ablehnt. –

+0

Ist der Code, an dem Sie gerade arbeiten, der einzige Einstiegspunkt für die Daten, auf die die Einschränkung verweist? Wenn ja, dann verlassen Sie sich absolut auf Ihre Codeschicht, um zu definieren, welche Werte gespeichert werden können. Der einzige Grund, den ich stelle, ist, weil ich an Legacy-Systemen gearbeitet habe, wo es mehrere Einstiegspunkte für Tabellen gibt, die nicht unbedingt in einem oder einem anderen Code definiert sind (siehe: weitläufige klassische ASP-Anwendungen) und eine Check-Einschränkung haben ist wichtig, um sicherzustellen, dass die ältere Codebasis nicht gegen referenzielle Integritäts- oder Eindeutigkeitsbeschränkungen verstößt. – antinescience

+0

Vollständig vereinbart - obwohl die Einschränkungen vorhanden sein sollten, um nur die Fälle zu schützen, in denen die oberen Ebenen der Validierung fehlschlagen. Ich habe auch einige Leistungstests durchgeführt: http://www.sqlperformance.com/2012/08/t-sql-queries/error-handling und http://www.mssqltips.com/sqlservertip/2632/ Überprüfung auf mögliche Constraint-Verletzungen-vor-Eingabe-SQL-Server-Try-and-Catch-Logik/ –

0

Ich habe so etwas wie dies:

public class SqlExceptionHelper 
{ 
    public SqlExceptionHelper(SqlException sqlException) 
    { 
     // Do Nothing. 
    } 

    public static string GetSqlDescription(SqlException sqlException) 
    { 
     switch (sqlException.Number) 
     { 
      case 21: 
       return "Fatal Error Occurred: Error Code 21."; 
      case 53: 
       return "Error in Establishing a Database Connection: 53."; 
      default 
       return ("Unexpected Error: " + sqlException.Message.ToString()); 
     } 
    } 
} 

Welche es wiederverwendbar sein können, und es erlaubt Ihnen, die Fehlercodes von SQL zu erhalten.

implementieren Dann einfach:

public class SiteHandler : ISiteHandler 
{ 
    public string InsertDataToDatabase(Handler siteInfo) 
    { 
      try 
      { 
       // Open Database Connection, Run Commands, Some additional Checks. 
      } 
      catch(SqlException exception) 
      { 
      SqlExceptionHelper errorCompare = new SqlExceptionHelper(exception); 
      return errorCompare.ToString(); 
      } 
    } 
} 

Dann wird es einige spezifische Fehler für gemeinsame Vorkommen bereitstellt. Aber wie oben erwähnt; Sie sollten wirklich sicherstellen, dass Sie Ihre Daten getestet haben, bevor Sie sie nur in Ihre Datenbank eingeben. Auf diese Weise entstehen keine nicht übereinstimmenden Beschränkungen oder existieren.

Hoffe es zeigt Sie in eine gute Richtung.

0

Hängt davon ab, was Sie versuchen zu tun. Einige Dinge zum Nachdenken:

  • Wo möchten Sie Ihren Fehler behandeln? Ich würde so nahe wie möglich an den Daten empfehlen.
  • Wen möchten Sie über den Fehler wissen? Muss Ihr Benutzer wissen, dass Sie diese ID bereits verwendet haben ...?
  • usw.

Auch - Einschränkungen gut sein können - ich weiß nicht 100% stimmt millimoose Antwort zu diesem Punkt - ich meine, ich in den sollte so sein/bessere Leistung ideal - aber Praktisch gesprochen, wenn Sie keine Kontrolle über Ihre Entwickler/qc haben, und insbesondere, wenn es darum geht, Regeln durchzusetzen, die Ihre Datenbank in die Luft jagen könnten (oder andere abhängige Objekte, wie Berichte usw., wenn ein Duplikatschlüssel irgendwo, brauchen Sie einige Barriere gegen (zum Beispiel) die doppelte Schlüsseleingabe

1

Ich würde eine gespeicherte Prozedur bevorzugen, die für potenzielle Verstöße vor dem Wurf prüft Daten auf SQL Server übertragen und die Einschränkung einen Fehler verursachen lassen. Die Gründe hierfür sind leistungsbezogen:

http://www.sqlperformance.com/2012/08/t-sql-queries/error-handling

http://www.mssqltips.com/sqlservertip/2632/checking-for-potential-constraint-violations-before-entering-sql-server-try-and-catch-logic/

Einige Leute werden dafür eintreten, dass Einschränkungen bei der Datenbankebene nicht notwendig sind, da Ihr Programm alles kann. Der Grund, warum ich mich nicht ausschließlich auf Ihr C# -Programm zur Erkennung von Duplikaten verlassen würde, ist, dass die Leute Möglichkeiten finden, die Daten zu beeinflussen, ohne Ihr C# -Programm durchlaufen zu müssen. Sie können später andere Programme einführen. Sie haben vielleicht Leute, die ihre eigenen Skripte schreiben oder direkt mit der Datenbank interagieren. Möchten Sie die Tabelle wirklich ungeschützt lassen, da sie Ihre Geschäftsregeln nicht berücksichtigt? Und ich denke nicht, dass das C# -Programm nur Daten an den Tisch werfen und auf das Beste hoffen sollte.

Wenn sich Ihre Geschäftsregeln ändern, möchten Sie Ihre App (oder alle anderen Apps) wirklich neu kompilieren? Ich schätze, das hängt davon ab, wie geschützt Ihre Datenbank ist und wie wahrscheinlich/oft Ihre Geschäftsregeln sich ändern.

3

sehe ich zwei Fragen hier, und hier ist mein nehmen ...

Datenbank Einschränkungen gut sind? Für große Systeme sind sie unabdingbar. Die meisten großen Systeme haben mehr als ein Frontend und sind nicht immer in kompatiblen Sprachen verfügbar, in denen die Logik zur Überprüfung der mittleren Ebene oder der Benutzerschnittstelle geteilt werden kann. Sie können Batch-Prozesse auch nur in Transact-SQL oder PL/SQL haben. Es ist in Ordnung, die Prüfung am Frontend zu duplizieren, aber in einer Multi-User-App ist die einzige Möglichkeit, die Eindeutigkeit wirklich zu überprüfen, der, den Datensatz einzufügen und zu sehen, was die Datenbank sagt. Gleiches gilt für Fremdschlüsseleinschränkungen - Sie wissen es erst, wenn Sie versuchen, es einzufügen/zu aktualisieren/zu löschen.

Sollen Ausnahmen ausgelöst werden oder sollten Rückgabewerte ersetzt werden? Hier ist der Code von der Frage:

try 
    { 
     // inset data 
    } 
    catch (SqlException ex) 
    { 
     if (ex.Message.ToLower().Contains("duplicate key")) 
     { 
      if (ex.Message.ToLower().Contains("url")) 
      { 
       return 1; // Sure, that's one good way to do it 
      } 
      if (ex.Message.ToLower().Contains("email")) 
      { 
       return 2; // Sure, that's one good way to do it 
      } 
     } 
     return 3; // EVIL! Or at least quasi-evil :) 
    } 

Wenn Sie, dass der anrufende Programm handeln garantieren kann tatsächlich auf der Grundlage der Rückgabewert, ich denke, die return 1 und return 2 sind am besten links nach Ihrem Urteil. Ich ziehe es vor, eine benutzerdefinierte Ausnahme für Fälle wie diese erneut auszulösen (zum Beispiel DuplicateEmailException), aber das bin nur ich - die Rückgabewerte werden auch den Trick tun. Schließlich können Verbraucherklassen Ausnahmen ebenso ignorieren wie Rückgabewerte.

Ich bin gegen die return 3. Dies bedeutet, dass eine unerwartete Ausnahme aufgetreten ist (Datenbank inaktiv, schlechte Verbindung, was auch immer). Hier haben Sie einen nicht spezifizierten Fehler, und die einzige diagnostische Information, die Sie haben, ist diese: "3". Stellen Sie sich vor, eine Frage zu SO zu stellen, die sagt Ich habe versucht, eine Zeile einzufügen, aber das System sagte '3'. Bitte beraten. Es wäre innerhalb von Sekunden geschlossen werden :)

Wenn Sie nicht wissen, wie eine Ausnahme in der Datenklasse zu handhaben, gibt es keine Möglichkeit einen Verbraucher der Datenklasse kann damit umgehen. An diesem Punkt sind Sie ziemlich abgespritzt, also sage ich, dass der Fehler protokolliert wird, und beenden Sie dann so elegant wie möglich mit der Meldung "Unerwarteter Fehler".

Ich weiß, dass ich ein wenig über die unerwartete Ausnahme rankte, aber ich habe zu viele Support-Anfragen bearbeitet, bei denen der Programmierer Datenbankausnahmen nur weiterverfolgte, und wenn etwas unerwartet kam, scheiterte die App entweder im Hintergrund oder fehlgeschlagen Information. Sehr frech.

Verwandte Themen