2009/03/31

我自己的框架RhinoLite (二) Unit Of Work

Unit of Work, 工作单元, 这个是本框架的核心部分, 负责配置, 初始化和管理nhibernate的Session, SessionFactory, 所以, 我们第一步从这里开始.

首先, 我们看看这个部分包含了哪些东西.



























通过类图我们可以看到, 我们有IUnitOfWork和IUnitOfWorkFactory, 前者掌管了Session, 所有的session的获取和dispose都由它负责. 在系统开发中, 需要开启事务等等也是可以由它来完成.

一般来说, 我们一般在一个操作之前创建一个UnitOfWork, 操作结束之后再dispose, 比如我们常见的web开发, 我们一般在beginrequest的时候创建, 在endrequest的时候dispose掉, 这就是所谓的 open-session-in-view模式, 使用这种模式能够方便地使用延迟加载, 简化session管理.

IUnitOfWorkFactory 很简单, 就是用来实例化IUnitOfWork的.

rhinolite 提供了UnitOfWork类, 简化Start, Dispose UnitOfWork, 初始化框架的操作.

ISessionFactoryManager 是对SessionFactory进行管理的类, 他也负责初始化nhibernate.

INHibernateInitializationAware 实现一些在初始化nhibernate过程中需要额外控制的部分, 这个用处很大, 后面大量的功能就是靠它实现

下面是UnitOfWork的序列图.


在nhibernate的配置和初始化, 我们采用了fluent nhibernate, 从而避免了繁琐的xml.

public virtual void InitializeRhinoLite()
{
RhinoLiteInitializer.Configure()
//.WithAutoLogging(@"..\..\log4net.config")
//.WithAutoTransaction()
.WithValidation()
.WithAuditSupport()
.UseNHibernate(f => f.ConfigureFlunetConfigureType())
.RegistServiceFrom();
}

public class FluentConfigurationProvider : IFluentConfigurationProvider
{
public List BuildFluentConfiguration()
{
var cfg = new Configuration();
var fluentConfiguration = Fluently.Configure(cfg)
.Database(MsSqlConfiguration
.MsSql2005
.ConnectionString(c =>
c.FromConnectionStringWithKey("TestConnection")
)
//because we want to execute sql to get dataset, we must use the extension driver.
//.Driver("RhinoLite.Common.Drivers.ExtSqlClientDriver,RhinoLite.Common")
.Driver()
.ShowSql()
.AdoNetBatchSize(100)
.QuerySubstitutions("true 1, false 0, yes 'Y', no 'N'")
)
.Mappings(m =>
m.HbmMappings.AddFromAssemblyOf() // use xml mappings here.
//m.FluentMappings.AddFromAssemblyOf()
//.AlterConventions(GetConventions)
);

return new List() { new CfgItem(cfg, fluentConfiguration) };
}
}

可以看到, 我们完全避免了hibernate.cfg.xml, 取而代之的是相对优美的fluent api, 这样做有几大好处, 便于测试, 最开始的版本我的配置信息基本都是用配置文件实现的(因为大量使用了castle的IoC), 现在我用简单的fluent api将其封装, 现在基本没有xml了.

我自己的框架RhiniLite (一) 前言

1. 起源
这个框架的灵感或者思想来源于大牛 Ayende (我是他的粉丝) 的 Rhino.Commons, Rhino.Commons这个框架主要是封装了nhibernate, castle activerecord等等类库, 令其更加方便. 正好我自己的几个项目也是使用的castle的IoC和activerecord, 所以对他的封装比较感兴趣. 当拜读了他的代码之后, 我发现几个问题, 比如他的依赖项目比较多, 比如他自己的CLR, Boo等几个项目, 我个人不是特别喜欢, 并且他的框架比较复杂. 所以我就从他的框架里面fork出一个版本, 起名为rhinolite, 意思就是他的rhino的轻量级版本. 去除了我认为不必要的依赖, 简化了框架. 经过几个月的断断续续的时间, rhinolite经历无数次的重构和大幅度的调整, 已经不再是rhino.commons的fork和轻量级版本了, 而是一个真正的完完整整的框架, 里面倾注我个人的思想和爱好, 基本上很少有rhino.commons框架的影子了(里面的repository代码还是借鉴了rhino.commons代码).

在编写这个框架的过程中, 我学到了很多东西, 虽然以前在使用castle ar, 但是对于nhibernate可谓只了解了皮毛, 现在了解nh, ar等等的初始化过程, 并且给castle, nhibernate, fluent nhibernate, rhino.commons都提交了好几个patch, 融入了open source project开发社区.

这个框架我参考了rhino.commons, sharp architecture, ncommon, fluent nhibernate, castle等等开源项目, 在此表示感谢.

2. 特色
说了这么多, 那么这个框架有什么特点呢?

a) 首先这个框架对nhibernate和activerecord进行了封装, 提供了完全一致的使用方法. rhino.commons也对nh和ar进行了封装, 但是实际上两者的风格并不统一. 而我个人的价值观是, 我只使用ar的attribute简化复杂的nh的xml的实体关系数据库映射, 而其他部分尽量和nh一致, 不使用任何ar自己的东西.
b) 对于持久层, 我使用了repository模式, ar不需要继承ar的基类, 在领域模型上不再有数据操作静态方法(我对于这个是深恶痛绝). repository提供了大量的基于Criteria的接口, 能够极大减少代码工作量.
c) 集成了Castle.Component.Validator, 使用nh2.0的event listener, 无缝集成.
d) 实现UnitOfWork模式, NHUnitOfWork简化了Session管理, 定义了SessionFactoryManager接口, 实现了完整的SessionFactory管理, 并且非常容易支持多数据库, 自动进行实体和对于的数据库或者SessionFactory关联.
e) 实现了预支持的Audit和SoftDelete操作
f) 完整简化的自动日志支持, 和castle的ATM自动事务支持类似, 只需要在记录异常日志的服务类上加上对应的attribute, 就行.
g) 对nh的query进行的简化操作和功能增强, 扩展了常见的数据库的driver, 现在可以执行sql语句, 返回dataset, 以及有带pagination的query.
h) 集成fluent nhibernate简化配置
i) 模仿fluent nhibernate的fluent api简化castle activerecord的配置

将来还会对微软的Windows Workflow Foundation进行封装, 让其支持多数据库.

下面是项目截图


3. 后续

我计划写一系列的文章来介绍整个架构.

超炫的界面原型设计软件 Balsamiq Mockups

前一段时间从 Ayende 的blog上看到一款界面原型设计软件 Balsamiq Mockups , 看起来非常酷, 当时在线试用了一下, 确实不错, 但是后来也没有继续关注了.

但是今天在邮件列表里面看到Ayende再次使用此工具画出了他的 Rhino Security 库的Admin界面草图, 如下图所示, 我一下子就明白了他所想要表达的意思, 非常直接和清楚. 平时我们日常开发或者沟通的时候可能也需要画出原型, 但是Visio或者写html往往比较麻烦和费时, 但是 Balsamiq Mockups 的出现, 我想真的改变了. 关键是Balsamiq Mockups 画出的图还非常酷, 我非常喜欢!



再来几张图片