你好,nhibernate的一些专业人士能给我一个每次会话或unhaddins实现的Nhibernate会话实例吗? 或解释如何做到这一点。 最好的祝福 Endiss
答案 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”没有“会话范围”,也没有实现“扩展持久化上下文”(“每会话策略会话”)的概念。
在此示例应用程序中,目标是演示:
expression="@(convCustomer)['CustomerEditController']"
。ISession.Get
到“相同记录”不会导致多次访问数据库,更有效地使用NHibernate缓存。对“CustomerList.aspx”的修改证明了这一点。要验证对话的有效性,请在“App_Code \ ConversationPage.cs”行this.Conversation.StartResumeConversation();
上发表评论,然后您会在点击“+”按钮时看到错误“未能懒惰地初始化角色集合” “CustomerList.aspx”。重要提示:切勿对整个应用程序使用单个对话(“HTTP会话”的持续时间相同)。请记住,NHibernate会保留所有已加载对象的缓存,如果对话持续很长时间,则此缓存趋于无限增长(限制是数据库记录的数量)。也就是说,每个会话应限于应用程序页面的子集,并且必须在与此子集(IConversationState.EndConversation()
)交互结束时被丢弃。建议:将<property name="EndPaused" value="true"/>
保留在“Spring.Conversation.Imple.WebConversationManager”中,这样当开始对话时,其他对象将被丢弃。
附加信息:单元测试(“Spring.Northwind.IntegrationTests.2008”)不起作用。但是没有问题,因为它与支持对话所做的更改无关,事实上它们甚至在此之前就已经导致了错误。
“Spring.Data.NHibernate.Northwind”中的更改列表:
的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>
IList<Customer> CustomersLoadedOncePerConvList
。列表只加载一次,每次会话只搜索一次数据库。Page_InitializeControls
以考虑CustomersLoadedOncePerConvList
。BtnShowOrders_Click
隐式地在Customer.Orders
上执行“延迟加载”。??? : Spring.Web.UI.Page
更改为??? : Spring.Web.UI.Page
:
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>