2011-02-01 5 views
3

私は、シングルティア,シングルユーザーアプリケーションと協力しています。FluentNHibernateです。複数のスレッドで、時間トリガーと着信ソケット・メッセージ・トリガーによってトリガーされます。私は、リポジトリの各メソッド内ISessionを配置/作成する、または私は多分プログラムから、複数の呼び出しを介してISessionのライフサイクルを維持する必要がある場合は終了し始めることができるかどうかを決定しますどのような要件NHibernateのセッションのライフサイクル。それぞれのリポジトリメソッドの内部で作成/処分するのはどうですか?

たとえば、遅延ロードはセッションを維持する必要がありますか?私がlazyloadを使用しない場合、他の何らかの理由で私はセッションを維持する必要がありますか?

は、現在、私のリポジトリ方法は以下のように見えるが、私は間違ったことをやっているのだろうか...

public class ProductRepository 
{ 
    public void Delete(Product product) 
    { 
     using (ISession session = FNH_Manager.OpenSession()) 
     { 
      using (ITransaction transaction = session.BeginTransaction()) 
      { 
       session.Delete(product); 
       transaction.Commit(); 
      } 
     } 
    } 

class FNH_Manager 
{ 
    private static Configuration cfg; 
    private static ISessionFactory sessionFactory; 

    public static void ConfigureSessionFactory() 
    { 
     sessionFactory = CreateSessionFactory(); 
    } 

    public static ISession OpenSession() 
    { 
     return sessionFactory.OpenSession(); 
    } 

EDIT1:「呼び出しごとにセッションを」処理する 試み:

public class EmployeeRepository 
    { 
     public static void Delete(Employee employee) 
     { 
      using (ISession session = FNH_Manager.OpenSession()) 
      { 
       using (ITransaction transaction = session.BeginTransaction()) 
       { 
        if (Employee.Id != 0) 
        { 
         var emp = session.Get(typeof(Employee), employee.Id); 
         if (emp != null) 
         { 
         session.Delete(emp); 
         transaction.Commit(); 
         } 
        } 
       } 
      } 
     } 
+0

自分自身に苦痛を与えずに、セッションを管理する作業単位を実装するだけです。実際にはコードが少なくなる可能性が高く、アプリケーションが異なるリポジトリから取得された複数のエンティティ間の複雑なやりとりを容易にする必要がある場合は、アプリケーションがさらに複雑になる場合はスケールアップされます。 – Brook

+0

@Brook - セッションはすでに作業単位です。 – Phill

+0

@Phil - それはありますが、自動的に変更のグループをラップするつもりはありません。そのためには、通常、特定のWebまたはwcfリクエストにスコープしたクラスでラップし、その作業ユニットを呼び出します。もう1つは、通常はNHの依存関係を持つアプリケーションの部分を望んでいないため、ラッパーを使用するとそれを切り離すことができます。 – Brook

答えて

5

遅延ロードされたフィールドを参照するときにセッションを開いておく必要があります。したがって、リポジトリ外の遅延ロードに頼っている場合は、セッションのライフスパンをどこか高いところで管理します。

遅延読み込みを使用しない場合は、1つのトランザクションで複数のアクションをサポートする必要があるかどうかも問題です。たとえば、ある製品や他のデータを一度に削除した場合、同じセッションで1つのトランザクションでそのデータを削除したい場合は、その製品を削除して、ある例外をスローし、データ、孤立したレコードまたはデータベースの破損状態で終了する可能性があります)。

1

削除された製品は、セッションに関連付けられていません。これは、いわゆる分離オブジェクトです。それを削除するなどのセッション内で使用するには、最初に現在開いているセッションに関連付ける必要があります。これを実現するにはいくつかの方法があります:

  1. セッションを開いたままにしておきます。同じセッションが、製品が削除されたときにロードされたときに開かれた場合、正常に動作します。
  2. オブジェクトをリロードしますが、ISession.Get()またはISession.Load()を使用してください。
  3. そうでない場合は、おそらくStaleStateException Sなどを取得しますISession.Lock()

で新しく開かれたセッションsessionにオブジェクトを再接続します。 NHibernate documentation

+0

ありがとう!これらの3つのポイントは本当に役に立ちました!私もドキュメントを読んでいますので、今理解してください。上記の私の編集はこの目的のために大丈夫ですか?そして、ISession.Lockで。これが私がリポジトリのUpdateメソッドで分離されたインスタンスに使用するものであることを意味しましたか?それは "削除"に関連していないように見えるので、私は正しいドキュメントを理解していれば? – bretddog

+0

喜んで助けてください!最初の読み込みと削除が同じセッションになるように、セッションの範囲を広げることがベストプラクティスと考えられますが、編集の外観はわかります。この最初のロードは、製品がデータベースから最初にフェッチされたときにコード例が開始される前に発生します。 ISession.Lockメソッドの名前はあまり良くありません。エンティティを再接続して操作をもう一度実行できるようにします。削除など。 – vidstige

+0

はい。私は最初のステップとしてセッションごとのセッションのテクニックを理解し、学びたいと思っています。それは貴重な学習経験だと思います。 LOCKについて:私はそれが "変更されていない"オブジェクトだけを受け入れると思っています。もし私が間違っていなければ、Isdirtyの例外がスローされます。したがってGetを使用する方がより頑強に見えました。しかし、それはデータベースに当たるが、そのようなローカルセッションスコープでは避けることはできないだろう。 – bretddog

3

上に読み込むための

思い出してくれる私はあなたがスレッドごとUnitOfWorkのパターンを使用すべきだと思います。 スレッド開始時にISessionを作成し、UnitOfWorkを初期化します。リポジトリにUnitOfWorkとその看板ISessionを使用します。スレッド実行の最後に、他のスレッドと競合があった場合に変更またはロールバックをコミットします。

+0

私はそれをどのように実装するのかは分かりません。各スレッドは、さまざまな場所でデータベースへの保存をトリガーする可能性のあるビジネスロジック全体の一連のイベントを開始できます。私はどのようにその視点でセッションを「保持」するかわかりません。 - これは、複数のスレッドに固有の問題がある場合を除き、 "セッションごとの呼び出し"で始めるほうが簡単です。 – bretddog

+0

@bretdogセッションスコープを管理する一般的な方法は、StructureMapやNinjectなどの依存性注入コンテナがそれを処理できるようにすることです。現代のコンテナには、「スレッドごと」、「リクエストごと」、「シングルトン」を管理する機能がありますので、心配する必要はありません。 – Brook

+0

@ブルック:あなたはこれらの言葉を参照してください "依存性注入"と "コンテナ"はまだ私が何を意味するか分からない事です。私たちがセッションを挿入できるセッションフィールド(?)を保持することができる、単一のクラスを考えると漠然としているかもしれませんが、クラスには多数のクラスがスレッドに関わっているので多くのクラスがデータベースにアクセスできます。だから私はそれにどのように接近するのか本当に分からない。それゆえ、私は最初の "セッションごとの呼び出し"の動機付けをしました。 – bretddog