NHibernate for Winforms with Spring.Net






4.67/5 (7投票s)
一个 Winforms NHibernate 框架代码生成。
引言
当我第一次研究 NHibernate
在 Winforms 环境中的用法时,我发现很少(甚至没有)文章能够普遍讨论这个主题或向初学者(像我一样)介绍它,这让我感到非常失望。因此,我决定将我的大部分发现总结到一篇文章中,提供一个框架,让刚接触 NHibernate 并即将在 Winforms 环境中使用它的开发人员可以找到一个起点。
虽然本文无意提供一套最佳实践,但我非常乐意收到任何建设性的反馈,以便最终能够创建一个类似于 Billy McCafferty 的 ASP.NET 的 NHibernate 最佳实践的 Winforms 版本。
背景
在阅读本文之前,我建议任何不熟悉“依赖注入”(DI)一词的人阅读 McCafferty 的 DI 文章,或者 Oren Eini 关于该主题的精彩论述。
您还需要 Spring.Net 框架(尽管任何其他容器都可以。在此示例中,我选择使用 spring)以及 SmartCode 代码生成工具。
Using the Code
现在,在 Winforms 中开始使用 NHibernate
时,您可能会首先注意到 Winforms 与 Web 环境的主要区别在于处理 session 的方式。在 Web 中,session 通常是按请求打开和关闭的。然而,这在 Winforms 中会变得更加复杂,因为没有请求,并且为每个窗口保留一个打开的 session 可能会导致 session 缓存变得非常庞大,仅仅因为一个窗口可能会比 ASP.NET 请求保持“活动”的时间更长。在多用户应用程序中,这还可能增加出现 StaleObjectStateException
的可能性。
看起来最合适解决方案是 Spring 论坛中 相当详细的文档。然而,这可能会导致另一个问题:懒加载模式,因为在您想要懒加载集合时,session 可能不会打开。对于这个问题,不幸的是,没有一个直接的答案,因为每个情况都应该单独考虑。更多信息可以在 Spring 论坛或我的另一篇文章 NHibernate 的 Lazy Initializer 中找到。
因此,在使用 spring 的事务属性和 TransactionManager
时,session 管理会变得不那么混乱。您只需要简单地将其属性添加到将调用数据访问层(DAL)的服务方法上,如下所示:
[Transaction(ReadOnly=false)]
public virtual void AccessMyDB()
{
// Do something with the db...
}
当使用 Spring 的 HibernateTemplate
在 DAL 中工作时,这将允许 spring 在需要时创建新 session 或获取已打开的 session(此外,在捕获异常时,事务默认会回滚。事务也可以在 spring XML 配置文件部分进行全局参数化)。
使用 spring 为我们创建的 HibernateDaoSupport
父类,使用 HibernateTemplate
会变得更加容易。我所做的是简单地创建了一个所有 DAO 都继承的基类,而基类又继承自 HibernateDaoSupport
。您可以在 spring 文档中找到更多关于 HibernateDaoSupport
的信息。
这种方法(为每个服务方法分配一个事务/session)将降低在多用户应用程序中处理 StaleObjectStateException
的概率。当处理两个用户不太可能同时修改相同实体/实体的应用程序时,您可以使用另一种方法,即 session 的生命周期可以跨越多个服务方法(有关更多信息,请参阅 Gustavo Ringel 的博客 - 感谢 Daniel M. Camenzind 的分享)。
至于“更高”的层次——用户界面和模型-视图层——我发现 MVP 模式是实现服务层和用户界面层之间更好分离的最优雅和最合适的解决方案。通过 MVP 模式,用户界面中不会直接找到任何服务代码,而是在“表示层”中。这样,如果有一天您想从 Winforms 迁移到 XAML,就可以插入全新的用户界面层。
更多关于模型-视图-演示者模式的信息可以在 Mike Peretz 的 关于使用 DI 进行 MVP 的文章中找到。
生成框架
现在,为了便于创建这样一个框架,我重写并扩展了 SmartCode 代码生成工具中的基模板。为什么选择 SmartCode 而不是其他做得很好的 NHibernate 代码生成工具?好吧,在我看来,SmartCode 能很好地完成工作,生成的代码非常简洁(这对我来说是最好的解决方案),并且高度可修改。此外,模板全部用 C# 编写,这对我很重要。如果您想修改模板以更好地适应您的需求,您会发现上手并不需要太长时间。这里有一篇关于 如何使用 SmartCode(由其创建者编写)的优秀文章;您可以从“SmartCode Projects”部分开始阅读。
您可以从页面顶部的链接下载模板。
现在您只需创建一个新解决方案,并添加以下项目:
MySolution.Core
MySolution.Data
MySolution.Services
MySolution.Presentation
以及您的 UI(如果您愿意,可以命名为
MySolution.UI
...)
然后,您应该在所有其他项目中添加对 Core 项目的引用。还应将 NHibernate 的引用添加到 Core 和 Data 项目。Data 项目应引用 Spring.Aop
、Spring.Core
、Spring.Data
、Spring.Data.NHibernate
、Spring.Data.NHibernate12
和 Spring.Services
DLL。Service 项目应引用 Spring.Core
、Spring.Data
和 Spring.Data.NHibernate12
DLL。
生成代码后,只需将生成的代码从您选择的文件夹拖放到相应的项目中:Core 文件夹的所有子文件夹到 Core 项目,Data 子文件夹到 Data 项目,依此类推。app.config.xml 文件的内容应复制到您的 app.config 文件中。这将包含您的 spring 配置。
我在 Northwind 数据库上生成的代码示例可以在 此处找到(一个 7.1 MB 的 zip 文件,因为这是整个解决方案,这也是我没有直接将其附加到文章中的原因)。我添加的唯一内容是 IEmployeeView
的 Form1
实现、IEmployeeView
的 LoadEmployeeById
事件以及 EmployeeController
中的 LoadEmployeeById
事件处理程序。
如果您觉得模板中缺少什么,请告诉我,我会尽力添加。
结论
我选择使用的模式绝不是处理 NHibernate
在 Winforms 中的最佳实践。本文仅用于总结我所学到的所有知识以及找到的关于该主题的资料。不幸的是,我在这方面的经验也很有限。我所做的只是将其他人的经验总结到一处。如果您想补充任何内容,或者您已经撰写了关于该主题的类似文章,请随时告知我。