每个会话示例的Nhibernate会话

时间:2012-04-11 12:41:42

标签: .net visual-studio nhibernate

你好,nhibernate的一些专业人士能给我一个每次会话或unhaddins实现的Nhibernate会话实例吗? 或解释如何做到这一点。 最好的祝福 Endiss

1 个答案:

答案 0 :(得分:3)

我和NHibernate一起工作了4年。以前我曾与"open-session-per-operation" antipattern合作过。对象总是分离的。因此,为了坚持,我必须重新附加它们或将它们的值复制到附加对象。这会导致许多行代码和许多“懒惰的初始化例程”。

最近,我研究了"Conversation pattern",并对"Spring.Net“基础架构进行了实施。该实施已在"jira.springsource"提交给Issue SPRNET-1431 (Workaround for 'conversation scope' and "session-per-conversation")

我没有提供“示例应用程序”,但如果您感兴趣,我可以这样做。

Hailton

补充答案:

我准备了示例应用程序并在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”。
  3. 重要提示:切勿对整个应用程序使用单个对话(“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"的引用,删除ref="CustomerEditController"并放置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。列表只加载一次,每次会话只搜索一次数据库。
      • 更改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();
    • 配置\ 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>