使用NHibernate和Spring.Net实现存储库

时间:2009-10-20 15:49:44

标签: nhibernate fluent-nhibernate domain-driven-design spring.net ddd-repositories

我正在尝试使用NHibernate,Fluent NHibernate和Spring。

遵循域驱动的设计原则,我正在编写一个由以下内容组成的标准分层Web应用程序:

  • 表示层(ASP.Net)
  • 业务层,包括:
    • 应用程序层(基本上是一组对UI层可见的方法)
    • 存储库接口和域组件(由应用程序层使用)
  • 持久层(基本上是业务层中定义的存储库接口的实现)

我想帮助确定一种实例化NHibernate ISession的方法,使得它可以在对业务层的单个请求的生命周期内由多个存储库共享。具体来说,我想:

  • 允许ISession实例和任何事务被存储库实现控制(可能是通过IOC框架的一些方面,拦截器?)

  • 允许ISession实例以测试友好的方式提供给存储库(可能通过注入或通过一些共享的“上下文”抽象)

  • 避免创建任何不必要的事务(即只执行只读操作时)

  • 允许我编写使用SQLLite的测试

  • 允许我使用Fluent NHibernate

  • 允许存储库实现保持对主机环境的无知。我还不知道businese层是否将在表示层中运行,或者将在WCF(在IIS中)下单独托管,所以我不想将我的代码绑定到HTTP上下文(例如)。

我第一次尝试解决这个问题一直是使用注册表模式;将ISession实例存储在ThreadStatic属性中。但是,随后的阅读表明这不是最佳解决方案(因为ASP.Net可以在页面生命周期内切换线程,我相信)。

任何想法,部分解决方案,模式名称,指向最新样本的指针(NHibernate 2)都将非常感激。

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的方法不是只读的理想时间。

总的来说,我认为这是解决所有问题的一种方法:

  • 允许会话管理在存储库外部
  • 可以在测试环境的上下文提供程序中模拟或指向ISession上下文
  • 避免不必要的交易(好吧,你必须颠倒我所做的事情并进行.Transactional()电话或其他事情)
  • 我不明白为什么你不能用SQLite测试,因为那更像是一个NHibernate的关注
  • 我自己使用Fluent NHibernate
  • 允许存储库忽略主机环境(即存储库调用者控制UoW存储上下文)

至于UoW的实施,在开始之前,我部分地试图不去寻找更多。有一个名为machine.uow的项目,据我所知,它很受欢迎,并且与NHibernate配合得很好。我没有玩过这么多,所以我不能说它是否像我自己写的一样整齐地解决了我的所有要求,但也可能节省了开发时间。

也许我们会得到一些关于我哪里出错或如何改进的评论,但我希望这在某些方面至少有帮助。

作为参考,我正在使用的软件堆栈是:

  • ASP.NET MVC
  • NHibernate上的流畅NHibernate
  • Ninject for dependency injection

答案 1 :(得分:1)

Spring.NET框架几乎开箱即用,支持您所描述的内容。仅对于FluentNHibernate,您需要在Spring.NET中添加自定义SessionFactory(不是很多代码,请看这里:Using Fluent NHibernate in Spring.NET)。

每个存储库都可以使用相同的ISession,只需在您的存储库中注入SessionFactory并使用Spring.NET的事务服务。

试试吧,他们有非常详尽的文档。