5

Was ist die beste Vorgehensweise beim Umgang mit Ausnahmen in NHibernate?Umgang mit NHibernate-Ausnahmen

Ich habe eine SubjectRepository mit folgendem bekam:

public void Add(Subject subject) 
    { 
     using (ISession session = HibernateUtil.CurrentSession) 
     using (ITransaction transaction = session.BeginTransaction()) 
     { 

      session.Save(subject); 
      transaction.Commit(); 
     } 
    } 

Und eine Einheit Test wie folgt:

 [Test] 
    public void TestSaveDuplicate() 
    { 
     var subject = new Subject 
     { 
      Code = "En", 
      Name = "English" 
     }; 

     _subjectRepository.Add(subject); 

     var duplicateSubject = new Subject 
     { 
      Code = "En", 
      Name = "English1" 
     }; 

     _subjectRepository.Add(duplicateSubject); 
    } 

ich zu dem Punkt, von dem Unit-Test erzeugt, um den Fehler der Handhabung und bin ein bisschen hängengeblieben. Dies schlägt wie erwartet fehl, obwohl ich mit einer GenericADOException eine ConstraintViolationException oder etwas Ähnliches erwartete (auf Datenbankebene gibt es eine Eindeutigkeitsbeschränkung für den Betreff-Code).

Die ADOException umschließt eine MySQL-Exception, die eine sinnvolle Fehlermeldung enthält, aber ich möchte nicht beginnen, die Kapselung durch einfaches Werfen der inneren Ausnahme zu unterbrechen. Zumal MySQL als Backend für dieses Projekt nicht abgeschlossen ist.

Idealerweise möchte ich in der Lage sein, die Ausnahme abzufangen und an diesem Punkt einen sinnvollen Fehler an den Benutzer zurückgeben. Gibt es dokumentierte Best-Practice-Ansätze für den Umgang mit NHibernate Exceptions und die Rückmeldung an den Benutzer, was schief gelaufen ist und warum?

Danke,

Matt

Antwort

13

Ich würde es in der Add-Methode als solche behandeln:

public void Add(Subject subject) 
{ 
    using (ISession session = HibernateUtil.CurrentSession) 
    using (ITransaction transaction = session.BeginTransaction()) 
    { 
     try 
     { 
      session.Save(subject); 
      transaction.Commit(); 
     } 
     catch (Exception ex) 
     { 
      transaction.Rollback(); 
      // log exception 
      throw; 
     } 
    } 
} 

Im catch-Block, sollten Sie zunächst die Transaktion Rollback und die Ausnahme protokollieren. Dann ist Ihre Optionen sind:

  1. Rethrow die gleiche Ausnahme, das ist, was meine Version tut
  2. es in Ihrem eigenen Ausnahme Wickeln und werfen, dass
  3. die Ausnahme Schlucken durch nichts zu tun, was sehr selten ist eine gute Idee

Sie haben keine echten Optionen für die Behandlung der Ausnahme in dieser Methode. Unter der Annahme, dass die Benutzeroberfläche diese Methode aufruft, sollte sie sie in ihrer eigenen try..catch aufrufen und sie behandeln, indem sie dem Benutzer eine sinnvolle Fehlermeldung anzeigt.Sie können den Komponententest mit dem Attribut ExpectedException (type) bestehen lassen.

Um Ihre Frage direkt zu beantworten, sollten Sie Ihren eigenen "sinnvollen Fehler" erstellen, indem Sie Exception erweitern und das mit der ursprünglichen Ausnahme als InnerException auslösen. Das ist die Ausnahme-Umhüllungstechnik, die ich in (2) aufgeführt habe.

+0

Ich denke, das Einwickeln der Ausnahme ist auch die beste Wahl. Die innere Ausnahme ist etwas in der Art von MySQLException Message = "Eintrag 'En' für Schlüssel 3". Da dies direkt vom Frontend aufgerufen wird, möchte ich eine sinnvolle Nachricht zurückgeben. –

+0

Ist das eine gute Idee, ALLE Ausnahmen zu fangen und zu verpacken? – VikciaR

+0

Sie können den Großteil dieses Codes entfernen, wenn Sie die Ausnahme gerade erneut auslösen. Wenn eine Transaktion nicht explizit festgeschrieben wird, wird sie beim Schließen der Sitzung zurückgesetzt (oder offensichtlich, wenn der Festschreibungsanruf eine Ausnahme auslöst) versuchen Sie es zurückzurollen), lassen Sie die Ausnahme einfach los und NH kümmert sich um die Transaktion, wenn sie nicht ausgeführt wurde - Sie erhalten die gleichen Effekte mit saubereren Code. –

1

Die allgemeine Frage sein wird, was wollen Sie den Benutzer sagen, und wer ist der Benutzer?

Wenn der Benutzer manchmal ein anderer Computer ist (d. H. Dies ist ein Webdienst), möchten Sie den entsprechenden Mechanismus verwenden, um einen SOAP-Fehler oder HTTP-Fehler zurückzugeben.

Wenn der Benutzer manchmal eine Benutzeroberfläche ist, dann möchten Sie vielleicht eine Nachricht für den Benutzer anzeigen, aber was würden Sie dem Benutzer sagen, damit er etwas dagegen tun kann? Zum Beispiel sagen die meisten Webseiten, "Entschuldigung, wir hatten einen unerwarteten Fehler", egal aus welchem ​​Grund. Das liegt daran, dass der Benutzer normalerweise nichts gegen den Fehler tun kann.

In beiden Fällen ist die Entscheidung, wie dem Benutzer zu sagen ist, eine Angelegenheit für die Präsentationsschicht (UI-Ebene), nicht für die DAL. Sie sollten möglicherweise Ausnahmen von der DAL in einen anderen Ausnahmetyp umwandeln, aber nur, wenn Sie die Nachricht ändern möchten. Sie benötigen keine eigene Ausnahmeklasse, es sei denn, Ihre Aufrufer würden etwas anderes tun, wenn es sich um eine Datenzugriffsausnahme und nicht um eine andere Art von Ausnahme handelt.

2

Alle Nhibernate-Ausnahmen sind nicht wiederherstellbar. Sie könnten das Design der App/Datenschicht erneut aufrufen, wenn Sie versuchen, von Nhibernate-Ausnahmen wiederherzustellen. Sie können auch spring.net 's ansehen exception translation implementaion Auch Sie manuell Transaktionen auf Ausnahmen behandeln ist mühsam und fehleranfällig, werfen Sie einen Blick auf nhibernate's contextual sessions. Spring.net hat auch einige nette Helfer rund um Nhibernate.

+0

NHibernate's kontextuelle Sitzung Link ist unterbrochen. –

+0

Der Link von NHibernate zur kontextuellen Sitzung von archive.org: https://web.archive.org/web/20090327153540/http://www.hibernate.org/hib_docs/nhibernate/1.2/reference/en/html/architecture.html –

1

Ich würde wahrscheinlich die Eingabe validieren, bevor Sie das Objekt speichern; Auf diese Weise können Sie die von Ihnen gewünschte Validierung implementieren (z. B. die Länge des Subjektcodes sowie die Tatsache, dass keine Dubletten vorhanden sind) und dem Benutzer sinnvolle Validierungsfehler zurückgeben.

Die Logik ist wie folgt; Ausnahmen werden verwendet, um außergewöhnliche Umstände anzuzeigen, die Ihr Programm nicht berücksichtigt. Ein Benutzer, der in Ihrem obigen Beispiel einen doppelten Subject Code eingegeben hat, sollte Ihr Programm bedienen. Anstatt eine Ausnahme zu behandeln, weil eine DB-Bedingung verletzt wird (was ein außergewöhnliches Ereignis ist und nicht auftreten sollte), sollten Sie dieses Szenario zuerst behandeln und nur versuchen, die Daten zu speichern, wenn Sie wissen, dass die Daten Sie Das Speichern ist korrekt. Der Vorteil bei der Implementierung aller Validierungsregeln in Ihrer DAL ist, dass Sie dann sicherstellen können, dass die in Ihre Datenbank eingehenden Daten gemäß Ihren Geschäftsprozessen konsistent sind, anstatt sich auf die Einschränkungen in Ihrer Datenbank zu verlassen die für dich.