5

NHibernateの例外を処理するためのベストプラクティスは何ですか?NHibernateの例外の処理

私は、次のとSubjectRepository持って次のように

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

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

とユニットテストを:

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

私はユニットテストによって生成されたエラーを処理するポイントになったとちょっと立ち往生した。これは期待どおりに失敗しますが、GenericADOExceptionでは、ConstraintViolationExceptionまたは類似のものが予想されています(データベースレベルの件名コードに一意性制約があります)。

ADOExceptionは、合理的なエラーメッセージを持つMySQL Exceptionをラップしますが、内部例外をスローするだけでカプセル化を中断したくないということです。特にMySQLはこのプロジェクトのバックエンドとして最終化されていません。

理想的には、私は例外をキャッチして、現時点でユーザに賢明なエラーを返すことができるようにしたいと考えています。 NHibernate Exceptionsを処理し、何がうまくいかなかったのか、そしてなぜそれをユーザーに報告するかに関する文書化されたベストプラクティスのアプローチはありますか?

おかげで、

マット

答えて

13

:catchブロックで

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

、あなたは最初のトランザクションをロールバックし、例外をログに記録する必要があります。次に、あなたのオプションは次のとおりです。私のバージョンは

  • 何をするかで同じ例外、再スロー

    1. は独自の例外で包みと
    2. は非常に稀に良いではありませんこれは、何もしないことにより、例外を飲み込むことを投げますidea

    このメソッドでは、例外を処理するための実際のオプションはありません。 UIがこのメソッドを呼び出すと仮定すると、それはそれ自身のtry..catchで呼び出され、ユーザーに意味のあるエラーメッセージを表示することによってそれを処理する必要があります。ExpectedException(type)属性を使用して、単体テストを合格させることができます。

    あなたの質問に直接答えるには、Exceptionを拡張して独自の「実用的なエラー」を作成し、元の例外をInnerExceptionとしてスローします。それは私が(2)で列挙した例外的なラッピング手法です。

  • +0

    私は例外をラッピングすることも最良の選択肢だと思います。 内部例外は、MySQLExceptionの行に沿ったものです。メッセージ= "重複するエントリ 'En'(キー3)。 これはフロントエンドから直接呼び出されるため、意味のあるメッセージを返すことにしたいと思います。 –

    +0

    すべての例外をキャッチしてラップするのは良い考えですか? – VikciaR

    +0

    このコードの大部分を削除することができます。トランザクションを明示的にコミットしないと、セッションが終了したときにロールバックされます(またはコミット呼び出しによって例外がスローされた場合それをロールバックしようとする)ので、例外を実行し、コミットしていなければNHがトランザクションを処理します - あなたはよりクリーンなコードで同じ効果を得るでしょう。 –

    1

    一般的な質問があることを行っている、あなたがユーザーに伝えるために何をしたいですか、およびユーザーのですか?

    ユーザが別のコンピュータ(Webサービス)になることがある場合は、適切なメカニズムを使用してSOAPフォールトまたはHTTPエラーを返す必要があります。

    ユーザーが何らかの並べ替えのUIになることがある場合は、ユーザーにメッセージを表示することができますが、ユーザーに何かを教えるように教えてください。たとえば、ほとんどのWebサイトでは、理由は関係なく、「申し訳ありませんが、予期せぬエラーが発生しました」と表示されます。これは、通常、ユーザーがエラーに関して何もできないためです。

    どちらの場合でも、「ユーザー」の表示方法の選択は、DALではなくプレゼンテーション層(UI層)の問題です。メッセージを変更する場合にのみ、別の例外タイプのDALから例外をラップする必要があります。呼び出し元が別の種類ではなくデータアクセス例外であれば、何か違うことをしない限り、独自の例外クラスは必要ありません。私のようなAddメソッドでそれを扱うでしょう

    2

    Nhibernateの例外はすべて回復不可能なので、nhibernateの例外から回復しようとしている場合は、app/dataレイヤーの設計を見直すことができます。 また、spring.netのexception translation implementaion も参照できます。また、例外のトランザクションを手動で処理するのは退屈でエラーが発生しやすいので、nhibernate's contextual sessionsをご覧ください。 Spring.netには、nhibernateの素晴らしいヘルパーもあります。

    +0

    NHibernateのコンテキストセッションのリンクが壊れています。 –

    +0

    archive.orgからのNHibernateのコンテクストセッションのリンクを処理する:https://web.archive.org/web/20090327153540/http://www.hibernate.org/hib_docs/nhibernate/1.2/reference/en/html/architecture.html –

    1

    おそらくオブジェクトを保存する前に入力を検証するでしょう。そうすれば、あなたは好きなバリデーション(たとえば、Subject Codeの長さや重複がないという事実をチェックする)を実装し、意味のある検証エラーをユーザーに返すことができます。

    ロジックは次のとおりです。例外は、プログラムが処理しない例外的な状況を示すために使用されます。上記の例で重複したサブジェクトコードを入力したユーザーは、プログラムでケータリングすべきものです。したがって、DB制約が違反する(例外的なイベントであり、発生してはならない)ため、例外を処理するのではなく、まずそのシナリオを処理して、データの保存を試みるだけです再保存は正しいです。

    DALにすべての検証ルールを実装することの利点は、DBに入るデータが、DBの制約を捉えるのではなく、一貫した方法でビジネスプロセスごとに有効であることを保証できることです。あなたのためのもの。