我正在尝试使用NHibernate,Fluent NHibernate和Spring。
遵循域驱动的设计原则,我正在编写一个由以下内容组成的标准分层Web应用程序:
我想帮助确定一种实例化NHibernate ISession的方法,使得它可以在对业务层的单个请求的生命周期内由多个存储库共享。具体来说,我想:
允许ISession实例和任何事务被存储库实现控制(可能是通过IOC框架的一些方面,拦截器?)
允许ISession实例以测试友好的方式提供给存储库(可能通过注入或通过一些共享的“上下文”抽象)
避免创建任何不必要的事务(即只执行只读操作时)
允许我编写使用SQLLite的测试
允许我使用Fluent NHibernate
允许存储库实现保持对主机环境的无知。我还不知道businese层是否将在表示层中运行,或者将在WCF(在IIS中)下单独托管,所以我不想将我的代码绑定到HTTP上下文(例如)。
我第一次尝试解决这个问题一直是使用注册表模式;将ISession实例存储在ThreadStatic属性中。但是,随后的阅读表明这不是最佳解决方案(因为ASP.Net可以在页面生命周期内切换线程,我相信)。
任何想法,部分解决方案,模式名称,指向最新样本的指针(NHibernate 2)都将非常感激。
答案 0 :(得分:1)
我没有使用过Spring.NET,所以我不能对此发表评论。然而,其余的声音非常明显(或者可能不那么显着;我们不是第一个实现这些东西;)类似于我自己的经验。我也很难找到一个真正的最佳实践,所以我尽可能多地阅读并提出了自己的解释。
在我的情况下,我希望事务/会话管理在存储库外部,并保持存储库关注点不被冒出来(即使用存储库的代码不需要知道它在内部使用NHibernate并且应该'我需要了解有关NHibernate会话管理的任何信息。在我的情况下,决定默认创建事务,以免开发人员忘记它们,所以我必须有一个只读的转义机制。我使用了工作单元模式,里面有NHibernate ISession实例存储。调用代码(我还为UoW创建了一个DSL接口)可能类似于:
using (var uow = UoW.Start().ReadOnly().WithHttpContext()
.InNewScope().WithScopeContext(ScopeContextProvider.For<CRMModel>())
{
// Repository access
}
在实践中,这可能与UoW.Start()
一样短,具体取决于已有多少上下文。 HttpContext
部分指的是UoW的存储位置,毫无疑问,在这种情况下是HttpContext
。正如您所提到的,对于ASP .NET应用程序,HttpContext
是最安全存储的地方。 ScopeContextProvider
基本上确保为UoW提供正确的数据上下文(ISession实例到相应的数据库/服务器,其他设置)。 “ScopeContext”概念还可以轻松插入“测试”范围上下文。
使用此路由会使存储库明确依赖于UoW接口。实际上,你可能会抽象一些,但我不确定我是否看到了它的好处。我的意思是,每个存储库方法检索当前的UoW实例,然后拉出ISession对象(或者只是那些不使用NHibernate的方法的SqlConnection)来运行NHibernate查询/操作。这对我有用,因为它似乎也是确保当前UoW对于可能需要运行CRUD的方法不是只读的理想时间。
总的来说,我认为这是解决所有问题的一种方法:
.Transactional()
电话或其他事情)至于UoW的实施,在开始之前,我部分地试图不去寻找更多。有一个名为machine.uow的项目,据我所知,它很受欢迎,并且与NHibernate配合得很好。我没有玩过这么多,所以我不能说它是否像我自己写的一样整齐地解决了我的所有要求,但也可能节省了开发时间。
也许我们会得到一些关于我哪里出错或如何改进的评论,但我希望这在某些方面至少有帮助。
作为参考,我正在使用的软件堆栈是:
答案 1 :(得分:1)
Spring.NET框架几乎开箱即用,支持您所描述的内容。仅对于FluentNHibernate,您需要在Spring.NET中添加自定义SessionFactory(不是很多代码,请看这里:Using Fluent NHibernate in Spring.NET)。
每个存储库都可以使用相同的ISession,只需在您的存储库中注入SessionFactory并使用Spring.NET的事务服务。
试试吧,他们有非常详尽的文档。