我在晚上的剩余时间里阅读了StackOverflow问题以及一些关于该主题的博客条目和链接。所有这些都证明是非常有帮助的,但我仍然觉得他们并没有真正回答我的问题。
所以,我正在开发一个简单的Web应用程序。我想创建一个可重用的数据访问层,稍后我可以在其他解决方案中重用它。其中99%将是Web应用程序。这似乎是我学习NHibernate及其周围模式的一个很好的借口。
我的目标如下:
考虑到这一切,我决定使用流行的存储库模式。我在这个网站和各种开发博客上阅读了这个主题,我听到了一些关于工作单元模式的内容。
我也环顾四周,检查了各种实现。 (包括FubuMVC contrib,SharpArchitecture,以及一些博客上的内容。)我发现大多数这些操作都遵循相同的原则:它们创建了一个“工作单元”,在实例化存储库时实例化,它们启动一个事务,做东西,提交,然后重新开始。因此,每ISession
只有一个Repository
,就是这样。然后客户端代码需要实例化一个存储库,用它做一些事情然后处理。
这种使用模式不符合我尽可能简单化的需要,所以我开始考虑别的事情。
我发现NHibernate已经有了使自定义“工作单元”实现变得不必要的东西,那就是CurrentSessionContext
类。如果我正确配置会话上下文,并在必要时进行清理,我很高兴。
所以,我想出了这个:
我有一个名为NHibernateHelper
的内部静态类。首先,它有一个名为CurrentSessionFactory
的静态属性,在第一次调用时,实例化会话工厂并将其存储在静态字段中。 (每ISessionFactory
一个AppDomain
就足够了。)然后,更重要的是,它具有CurrentSession
静态属性,用于检查当前是否绑定了ISession
会话上下文,如果没有,则创建一个并绑定它,并返回绑定到当前会话上下文的ISession
。
因为它主要用于WebSessionContext
(因此,每个ISession
一个HttpRequest
,但对于单元测试,我配置了ThreadStaticSessionContext
),它应该无缝地工作。在创建并绑定ISession
之后,它会将事件处理程序挂钩到HttpContext.Current.ApplicationInstance.EndRequest
事件,该事件在请求结束后负责清理ISession
。 (当然,只有当它真正在Web环境中运行时才会这样做。)
因此,通过所有这些设置,NHibernateHelper
将始终能够返回有效的ISession
,因此无需为“工作单元”实例化存储库实例正常。相反,Repository
是一个静态类,它使用ISession
属性中的NHibernateHelper.CurrentSession
进行操作,并通过泛型方法公开功能。
所以,基本上,我最终得到了两个非常懒惰的单身人士。
我很好奇,你怎么看待这个? 这是一种有效的思考方式,还是我完全偏离这里?
修改
我必须指出NHibernateHelper类是内部的,因此对于存储库的使用者来说几乎是不可见的。
另一个想法是,为了将依赖注入引入解决方案,是创建一个名为IDataProvider
的接口,并在第一次调用Repository
类时实例化该实例。 (但是,实现代码也应该能够关注上下文的概念。)
编辑2:
似乎很多人都喜欢我的想法,但在答案中对它的看法仍然太少
我可以假设这是使用NHibernate的正确方法吗? :P
答案 0 :(得分:2)
对于它的价值,夏普建筑正在或多或少地完全按照你的建议行事。它最终为每个HTTP请求提供一个会话(更准确地说,每个HTTP请求每个数据库一个会话)。您的方法肯定是有效的,并且每个请求也提供一个会话。我更喜欢SharpArch更清洁的OO方法,通过DI使用静态存储库和辅助类。
答案 1 :(得分:1)
我们混合了ASP.NET / Windows Forms应用程序,我发现最好的解决方案是通过存储库构造函数进行手动依赖注入。也就是说,每个存储库类都有一个需要ISession的公共构造函数。这允许应用程序完全控制工作单元和事务边界。它简单而有效。我还有一个非常小的NHibernate助手程序集,它配置会话工厂并提供打开常规或上下文会话的方法。
关于S#arp架构我有很多喜欢的东西,我认为值得研究它是如何工作的,但我发现它的架构过于符合我的口味。