1

こんにちは、nhibernate の一部のプロが、会話ごとの Nhibernate セッションまたは unhaddins 実装の実装例を教えてくれますか? または、その方法を説明してください。よろしくエンディス

4

1 に答える 1

3

私は NHibernate を 4 年間使用しています。以前は、「open-session-per-operation」アンチパターンを使用していました。オブジェクトは常に切り離されていました。したがって、永続化するには、それらを再アタッチするか、それらの値をアタッチされたオブジェクトにコピーする必要がありました。これにより、多くのコード行と多くの「遅延初期化例外」が発生します。

最近、私は「会話パターン」を研究し、 「Spring.Net」インフラストラクチャ上で実装を行いました。この実装は、Issue SPRNET-1431 (「会話スコープ」および「セッションごとのセッション」の回避策)で「jira.springsource」に提出されました。

「サンプルアプリ」は作っていませんが、興味があれば作れます。

ハイルトン

補足回答:

サンプルアプリを用意し、SPRNET-1431 Workaround for 'conversation scope' and "session-per-conversation" にファイル "Spring.Conversation.example.7z" として投稿しました。

以下に、私が何をしたかを明確にする(またはしない)ための説明を書きました。

この「サンプルアプリ」は、「Spring.NET」のバージョン「1.3.0」に含まれる「Spring.Data.NHibernate.Northwind」をConversationを利用するために改変したものです。現在、「Spring.Net」には「会話スコープ」がなく、「拡張永続コンテキスト」(「会話戦略ごとのセッション」) の概念も実装されていません。

このサンプル アプリケーションの目的は次のとおりです。

  1. オブジェクトのインスタンスを「会話範囲」の模倣に保持する方法。に示されていexpression="@(convCustomer)['CustomerEditController']"ます。
  2. 「拡張永続コンテキスト」の楽しみ方。「遅延読み込みエラー」は発生しなくなりISession.Get、「同じレコード」への呼び出しが繰り返されても、データベースへの多数のアクセスが発生せず、NHibernate キャッシュがより効率的に使用されます。"CustomerList.aspx" の変更は、これを示しています。会話の有効性を確認するには、「App_Code\ConversationPage.cs」行にコメントを付けますthis.Conversation.StartResumeConversation();。「CustomerList.aspx」の「+」ボタンをクリックすると、「ロールのコレクションを遅延初期化できませんでした」というエラーが表示されます。 .

重要: アプリケーション全体で 1 つの会話を使用しないでください (「HTTP セッション」の期間は同じです)。NHibernate は、ロードされたすべてのオブジェクトのキャッシュを保持します。会話が長時間保持されると、このキャッシュは無限に大きくなる傾向があります (制限はデータベース レコードの量です)。つまり、各会話はアプリケーション ページのサブセットに制限する必要があり、このサブセットとの対話の最後に破棄する必要があります ( IConversationState.EndConversation())。推奨事項: <property name="EndPaused" value="true"/>「Spring.Conversation.Imple.WebConversationManager」に保持して、会話を開始すると、他の会話は破棄されます。

追加情報: 単体テスト ("Spring.Northwind.IntegrationTests.2008") が機能していません。ただし、会話をサポートするための変更とは関係ないため、問題はありません。実際には、それ以前にも既にエラーが発生していました。

「Spring.Data.NHibernate.Northwind」の変更点のリスト:

  • Spring.Northwind.Web.References.2008
    • スキームへのリンクを追加してオートコンプリートを有効にします。
  • web.config

    • モジュール、追加:

      <add 
        name="ConversationModule" 
        type="Spring.Conversation.HttpModule.ConversationModule, Spring.Conversation"/>  
      <add 
        name="ConversationModule" 
        type="Spring.Conversation.HttpModule.ConversationModule, Spring.Conversation"/>
      
    • モジュール、削除:

      <add 
        name="OpenSessionInView" 
        type="Spring.Data.NHibernate.Support.OpenSessionInViewModule, Spring.Data.NHibernate21"/>
      
  • web.xml

    • モジュール構成

      <!--Configuration for Spring HttpModule interceptor's-->
      <object 
         name="HttpApplicationConfigurer" 
         type="Spring.Context.Support.HttpApplicationConfigurer, Spring.Web">
        <property name="ModuleTemplates">
          <dictionary>
            <entry key="ConversationModule">
              <!-- this name must match the module name -->
              <object>
                <!-- 
                select "view source" in your browser on any page to 
                see the appended html comment
                -->
                <property name="ConversationManagerNameList">
                  <list element-type="string">
                    <value>conversationManager</value>
                  </list>
                </property>
              </object>
            </entry>
          </dictionary>
        </property>
      </object>
      
    • 会話マネージャー

      <!--Conversation Manager-->
      <object 
          name="conversationManager" 
          type="Spring.Conversation.Imple.WebConversationManager, Spring.Conversation" 
          scope="session">
        <property name="SessionFactory" ref="NHibernateSessionFactory"/>
        <property name="EndPaused" value="true"/>
      </object>
      
    • お客様との会話

      <!--
       Conversation for 'CustomerEditor.aspx', 'CustomerList.aspx', 
       'CustomerOrders.aspx', 'CustomerView.aspx',  and 'FulfillmentResult.aspx'
      -->
      <!--
       Important: If the application had other parties
       ("management employees" for example), they should use another 
       conversation.
      -->
      <object 
          name="convCustomer" 
          type="Spring.Conversation.Imple.WebConversationSpringState, Spring.Conversation" 
          scope="session">
        <property name="Id" value="convCustomer"></property>
        <property name="TimeOut" value="0"></property>
        <property name="ConversationManager" ref="conversationManager"></property>
        <property name="SessionFactory" ref="NHibernateSessionFactory"/>
        <property name="DbProvider" ref="DbProvider"/>
        <!--
          Using workaround for 'conversation scope' to reference for 
          'CustomerEditController'. It is not as volatile as "request scope" 
          not as durable as the "session scope"
        -->
        <property name="['CustomerEditController']" ref="CustomerEditController"></property>
      </object>
      
    • 「CustomerEditController」スコープを変更し、[scope="session"] を削除して [singleton="false"] を配置します。

      <object 
          name="CustomerEditController" 
          type="NHibernateCustomerEditController" 
          singleton="false">
        <constructor-arg name="sessionFactory" ref="NHibernateSessionFactory"/>
      </object>
      ...
      
    • "CustomerEditController"、removeref="CustomerEditController"および putの参照を変更しますexpression="@(convCustomer)['CustomerEditController']"(「会話範囲」をシミュレートします):

      <!--
        Using workaround for 'conversation scope' to reference for 
        'CustomerEditController'. It is not as volatile as "request scope" 
        not as durable as the "session scope"
      -->
      <object name="CustomerEditPage" abstract="true">
        <property 
          name="CustomerEditController" 
          expression="@(convCustomer)['CustomerEditController']"/>
        <property name="Conversation" ref="convCustomer"/>
      </object>
      
        <!--
          Using workaround for 'conversation scope' to reference for 
          'CustomerEditController'. It is not as volatile as "request scope" 
          not as durable as the "session scope"
        -->
        <object type="CustomerView.aspx">
          <property name="CustomerDao" ref="CustomerDao" />
          <property 
            name="CustomerEditController" 
            expression="@(convCustomer)['CustomerEditController']" />
          <property name="Conversation" ref="convCustomer"/>
          <property name="Results">
            <dictionary>
              <entry key="EditCustomer" value="redirect:CustomerEditor.aspx" />
              <entry key="CustomerList" value="redirect:CustomerList.aspx" />
            </dictionary>
          </property>
        </object>
        <!--
          Using workaround for 'conversation scope' to reference for 
          'CustomerEditController'. It is not as volatile as "request scope" 
          not as durable as the "session scope"
        -->
        <object type="FulfillmentResult.aspx">
          <property name="FulfillmentService" ref="FulfillmentService" />
          <property 
            name="CustomerEditController" 
            expression="@(convCustomer)['CustomerEditController']" />
          <property name="Conversation" ref="convCustomer"/>
          <property name="Results">
            <dictionary>
              <entry key="Back" value="redirect:CustomerOrders.aspx" />
            </dictionary>
          </property>
        </object>
        <object type="Default.aspx">
          <property name="Conversation" ref="convDefault"/>
          <property name="Results">
            <dictionary>
              <entry key="CustomerList" value="redirect:CustomerList.aspx" />
            </dictionary>
          </property>
        </object>
        <!--Conversation for 'Default.aspx'-->
        <!--
          "convDefault" will have only one functionality: trigger the release
          of other conversations when started (StartResumeConversation())
        -->
        <object
            name="convDefault" 
            type="Spring.Conversation.Imple.WebConversationSpringState, Spring.Conversation"
            scope="session">
          <property name="Id" value="convDefault"></property>
          <property name="TimeOut" value="0"></property>
          <property name="ConversationManager" ref="conversationManager"></property>
          <property name="SessionFactory" ref="NHibernateSessionFactory"/>
          <property name="DbProvider" ref="DbProvider"/>
        </object>
  • 「ConversationPage.cs」を追加しました。会話をサポートするベースページ。
  • CustomerList.aspx
    • 「遅延初期化エラー」なしで、同じページの「注文」をリストに許可します。すべてのオブジェクトは ISession (NHibernate) に接続されたままです。
  • CustomerList.aspx.cs:
    • プロパティを追加しましたIList<Customer> CustomersLoadedOncePerConvList。リストは 1 回だけ読み込まれ、会話ごとに 1 回だけデータベースを検索します。
    • を変更しPage_InitializeControlsて検討しCustomersLoadedOncePerConvListます。
    • このメソッドBtnShowOrders_Clickは、 に対して暗黙的に「遅延ロード」を実行しCustomer.Ordersます。
  • ??? : Spring.Web.UI.Pageオンに変更??? : Spring.Web.UI.Page:
    • CustomerEditor.aspx.cs
    • CustomerList.aspx.cs
    • CustomerOrders.aspx.cs
    • CustomerView.aspx.cs
    • FullfillmentResult.aspx.cs
    • Default.aspx.cs
  • Dao.xml

    • <entry key="connection.release_mode" value="on_close"/>各 IDbCommand 実行前後の切断と再接続を回避するために追加されました。トランザクションの境界外で多数の遅延ロードが発生する可能性があるため、これは重要です。
    • 追加した:

      ...
      <entry key="show_sql" value="true"/>
      <entry key="format_sql" value="true"/>
      ...
      
  • 「Default.aspx.cs」から削除します (使用されません)。

    • customerDao;
    • fulfillmentService;
    • CustomerDao;
    • Button1_Click(object sender, EventArgs e);
    • ProcessCustomer();
  • Config\Log4Net.xml。

    ...
    <!--detail's about SQL's. To view sql commands on Logs\log.txt-->
    <logger name="NHibernate.SQL">
      <level value="DEBUG" />
    </logger>
    ...
    <!--detail's about Conversation-->
    <logger name="Spring.Conversation">
      <level value="DEBUG" />
    </logger>
    
于 2012-04-23T01:55:14.703 に答える