5

Qual è la procedura migliore per la gestione delle eccezioni in NHibernate?Gestione delle eccezioni NHibernate

Ho un SubjectRepository con il seguente:

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

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

E una prova di unità come segue:

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

sono arrivato al punto di gestire l'errore generato dal test di unità e rimasto un po 'bloccato Ciò non riesce come previsto, anche se con una GenericADOException mi aspettavo una ConstraintViolationException o qualcosa di simile (esiste un vincolo di univocità sul codice dell'oggetto a livello di database).

ADOException include un'eccezione MySQL con un messaggio di errore ragionevole ma non desidero iniziare a interrompere l'incapsulamento semplicemente lanciando l'eccezione interna. Soprattutto perché MySQL non è finalizzato come back-end per questo progetto.

Idealmente mi piacerebbe essere in grado di catturare l'eccezione e restituire un errore ragionevole all'utente a questo punto. Esistono approcci di best practice documentati per gestire le eccezioni NHibernate e riportare all'utente che cosa è andato storto e perché?

Grazie,

Matt

risposta

13

vorrei gestirlo nel metodo Add come tale:

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

Nel blocco catch, si deve prima rollback della transazione e registrare l'eccezione. Quindi le opzioni sono:

  1. rigenerare la stessa eccezione, che è quello che la mia versione fa
  2. avvolgerla nella propria eccezione e buttare che
  3. ingoiare l'eccezione non facendo nulla, che è molto raramente una buona idea

Non si dispone di opzioni reali per la gestione dell'eccezione in questo metodo. Supponendo che l'interfaccia utente chiami questo metodo, dovrebbe chiamarlo nel proprio try..catch e gestirlo visualizzando un messaggio di errore significativo per l'utente.Puoi eseguire il test del tuo dispositivo utilizzando l'attributo ExpectedException (type).

Per rispondere direttamente alla domanda, è necessario creare il proprio "errore ragionevole" estendendo Eccezione e gettarlo con l'eccezione originale come InnerException. Questa è la tecnica di wrapping delle eccezioni che ho elencato in (2).

+0

Penso che avvolgere l'eccezione sia l'opzione migliore. L'eccezione interna è qualcosa sulla falsariga di MySQLException Message = "Duplica voce 'En' per la chiave 3". Dato che questo sarà chiamato direttamente dal front-end, vorrei restituire un messaggio significativo. –

+0

Questa è una buona idea, per cogliere TUTTE le eccezioni e avvolgerla? – VikciaR

+0

Puoi rimuovere la maggior parte di questo codice, se stai solo rilanciando l'eccezione - se una transazione non è impegnata in modo esplicito, verrà ripristinata quando la sessione si chiude (o, ovviamente, se la chiamata di commit genera un'eccezione tentare di ripristinarlo), quindi lascia andare l'eccezione e NH si prenderà cura della transazione se non ha eseguito il commit - otterrai gli stessi effetti con un codice più pulito. –

1

La questione generale sta per essere, cosa vuoi dire l'utente, e chi è l'utente?

Se l'utente a volte è un altro computer (ad esempio, questo è un servizio Web), quindi si desidera utilizzare il meccanismo appropriato per restituire un errore SOAP o HTTP.

Se l'utente a volte è un'interfaccia utente di qualche tipo, è possibile che si desideri visualizzare un messaggio all'utente, ma cosa diresti all'utente in modo che possa fare qualcosa al riguardo? Ad esempio, la maggior parte dei siti web dirà "mi dispiace, abbiamo avuto un errore imprevisto", indipendentemente dal motivo. Questo perché di solito non c'è nulla che l'utente possa fare riguardo all'errore.

Ma in entrambi i casi, la scelta di come dire "l'utente" è una questione per il livello Presentazione (livello UI), non per il DAL. È consigliabile includere le eccezioni del DAL in un altro tipo di eccezione, ma solo se si intende modificare il messaggio. Non hai bisogno della tua classe di eccezione, a meno che i chiamanti facciano qualcosa di diverso se si tratta di un'eccezione di accesso ai dati piuttosto che di un altro tipo.

2

Tutte le eccezioni di Nhibernate non sono ripristinabili, è possibile rivisitare il design del livello applicazione/dati se si sta tentando di ripristinare da eccezioni nhibernate. Puoi anche dare un'occhiata a spring.net. exception translation implementaion Anche tu gestisci manualmente le transazioni su eccezioni è noioso e soggetto a errori, dai un'occhiata a nhibernate's contextual sessions. Spring.net ha anche alcuni simpatici aiutanti in giro per il divieto.

+0

Il collegamento della sessione sestuosa di NHibernate è interrotto. –

+0

Utilizzo del collegamento della sessione di NHibernate da archive.org: https://web.archive.org/web/20090327153540/http://www.hibernate.org/hib_docs/nhibernate/1.2/reference/en/html/architecture.html –

1

Probabilmente avrei convalidato l'input prima di salvare l'oggetto; in questo modo puoi implementare qualsiasi convalida che ti piace (ad esempio, controlla la lunghezza del Codice soggetto, oltre al fatto che non ci sono duplicati) e restituisci all'utente errori significativi di validazione.

La logica è la seguente; le eccezioni sono usate per indicare circostanze eccezionali che il tuo programma non soddisfa. Un utente che immette un codice oggetto duplicato nell'esempio sopra riportato è qualcosa per cui il programma deve essere utilizzato; quindi, piuttosto che gestire un'eccezione perché viene violato un vincolo di DB (che è un evento eccezionale e non dovrebbe verificarsi), dovrai prima gestire lo scenario e tentare di salvare i dati solo quando sai che i dati il salvataggio è corretto.

Il vantaggio con l'implementazione di tutte le regole di convalida nel DAL è che è possibile quindi garantire che i dati inseriti nel DB siano validi secondo i processi aziendali in modo coerente, anziché fare affidamento sui vincoli nel DB per rilevare quelli per te