面向对象设计,ORM,NHIBERNATE杂谈(有感)
ORM设计实际上是一个O到D的过程,就是由对象,最终生成数据实体.但是,问题在于传统的设计我们必须设计一次业务对象,再重复设计一次关系对象(当然也可能是其他形式的存储对象),这种方法实际上是两张皮,而且这是一个重复的过程.但是由于现在尚未有面向对象的DBMS所以我们必须将O的设计按关系数据库再实现成表.
想想看,我们平常设计一个对象,需要设计若干个属性,每一个属性,会有数据类型,数据长度,有效性规则等,而这些,在数据库的实体里是一一对应的,如果能实现一次设计就好了.于是,包括我在内的许多人,使用的是由D到O的设计方式,就是首先用DBMS提供的实体设计工具,设计出实体,然后再用C#去写对应的对象.
这里有两个问题,第一是,这样使我们的程序员不得不同时做DBA和程序员两份工作,第二,业务对象和关系表结合的如此紧密,以致于当我们更换DBMS时,我们不得不再次重新设计关系实体或用其他工具实现转换.最重要的是后续的工作,想想我都害怕,因为业务对象往往是随时变化的,每一次变化,你不得不去修改大量的代码,同时还要去保持关系数据表的同步变化,这不光是一个量大的工作,同时也是一个非常细致,并且是繁琐的工作.
不知道别人是怎么处理的,不过,这种传统的设计方法也有快速的解决方案,就是有人设计出业务对象后,然后利用诸如CodeSmith或其他的代码生成工具,从关系表中导出业务对象,同时生成其基本的CRUD操作.是的,我也这么用过,它确实减轻了我不少的工作量,并且,CODESMITH是我见过的最棒的伸缩性最强,最易用的生成工具(不仅仅是代码,任何可使用模板解决,甚至是邮件合并,它都能轻松完成).可是,这只是减轻了开发时的工作量,其后的扩展和维护工作,没有任何工具能帮上我们的忙.另外,这种设计方法对于小项目确实不错,如果可以的话,你还可以引入MS的ENTERPRISE LIBRARY中的数据存取快,进一步提高扩展性.但是,这种方式仍然是倒行逆施的.跟现在流行的面向对象设计方法是相违背的,很多人认为面向对象的设计方法加重了工作量,对于小的项目,确实如此,并且,对于小项目,我也不推荐使用面向对象设计,而且甚至我也不推荐分层的设计方法,原因无它,分层设计本来的目的不是加快开发速度,而是增加系统扩展性和灵活性.在小项目中使用三层结构和面向对象是得不偿失的.所以,对于一般小项目,我也是将业务逻辑和数据存取两层合并起来.所以,对于分层,当然是要看情况而定.而至于面向对象的设计方法,当然是不可逆挡的潮流,甚至DBMS也有一天会面向对象.为什么呢?个人认为这是最为效法自然的方式.毕竟计算机以及其上的技术都是人类发明的,且是对人类现有知识的体现和拓展.其实面向对象这个东东是我们生活中最为常见的表现手法,例如你要去描写一个人或一件物,你就会定义其属性.
回到正题,那Nhibernate是什么东东呢?你可以看看NHibernate的帮助档,其中有一个架构图清晰的表示出NHibernate是业务对象与数据实体之间的桥梁.这个架构中称NHibernate为Persist Object为持久对象.(持久这个词翻译的实在不怎么样,以前MS在VC里叫它Serialize,称续列化,反正这些词是MS发明的).持久化对象的责任就是负责将对象永久存储,而数据实体就是存储后的形式,例如,橙子对象的一个实例Org,它的属性如下:
颜色:黄色
重量:250g
等级:一级
.....
通过NHibernate你就可以将其存储到数据库的一个表:orange中,成为一个Record
而你需要做的是三件事:
1,定义一个类表示橙
2,写一个让NHibernate可以看得懂的配置文件,告诉它你使用何种DBMS,使用何种SQL语言,使用何种连接串跟数据源连接.写一个映射文件将你写的橙这个业务类跟DBMS中的Orange表关联起来
3,为橙这个对象写出保存,更新,删除的方法即可.
听起来不错,业务对象和数据表好比一个事物的两种表现形式,而NHibernate的作用就是把对象的表现形式转换成数据表的表现形式,但是NHibernate也不是万能的,所以,我们得写映射文件告诉NHibernate如何去转换(用过SQL的DTS的人都可以想想这个类似的过程吧)
那么这样我还不是的手工的去建这个Orange表吗?NO,NO,如果Nhibernate不能生成数据表,那么它就不是那么完美的,但是,Nhibernate完全可以完成数据表的生成,修改和删除,这部分功能在NHibernate.Tools.Hbm2DDL命名空间已经实现,也就是说NHibernate完全可以根据OR映射文件.hbm.xml来生成对应的数据表.而且,通过修改配置文件,还可以生成与对应DBMS相适应的数据表.
另外一点,如果使用Nhibernate,还有一个好外,举个例子来说,有一天,突然,主管叫你说,橙子现在应市场部要求,要打上"原产地"这一项标签,按我的经验来说,这是经常的事,类似的事还有,规则的变更,比如,以前重量必须大于200g,现在要求必须大于250g,类似的规则我的变化(这在DBMS里叫约束)
针对上述描述的场景,使用NHibernate实现的项目,你所要做的是为业务对象Org添加一个新属性:原产地,并且为其Set属性设置器作一个规则判断,不合规则,则抛出异常并处理.同时,为该对象的映射文件.hbm.xml添加一个新的Property映射,最后,在具体使用该对象的地方为"原产体"属性加入赋值即可.一切OK
但是,假如你不是用ORM的方式去设计,而是像我以前那样将业务对象和数据实体分开设计,然后写自己的业务对象操作类来完成对数据实体的操作(这是很常见的,像MS的PETSHOP就是,这种方式也有面象服务和面象对象之分,区别在于,面向服务是定义一个拥有静态方法的类,将要操作的对象属性做为参数传入,而面向对象的方法,则需要写一个业务对象,并为其定义属性,然后在其中定义方法以实现CRUD.两个方法各有千秋,前一种方法,无需实例化对象,因为基本上没有业务对象,只是将业务对象的"属性"做参数传入并处理,因此,节省资源.但是,后一种方法更灵活),无论如何,这种情况下,你要完成这种业务对象或规则的变更,都是一件需要极其小心的事,因为你可能要做以下操作:
1,修改数据表以使其符合新的业务对象
2,修改业务对象(如果使用面向对象而不是服务)
3,修改参数(如果使用面向服务,则需要添加或移除各个静态方法传入的参数)
你必须保证每一处小的改动都在业务对象和数据实体间保持完全一致,否则,小小的错误就可能导致问题出现
跟前面的分层设计和面向对象一样,ORM从一出现到现在,也是面临种种争执,不过,这完全是正常的,因为,大家看问题的角度和层面不一样,而且大家的需求也不尽一致,所以,无需怀疑ORM的必要性,对有用的人来说,它就是宝贝和武器,对于暂时不需要它的人来说,它可能是鸡肋.不过,至少从我的体会来说,我觉得它真的解决了我的困扰,这才是最重要的
另外,说明一下,ORM不等于NHibernate,只不过,NHibernate名气太大了,以致于一提起ORM,人们就想起它,其实它不是新鲜的东西,它是JAVA下的Hibernate框架移植到.NET上的实现,实际上,有很多人也写过ORM框架,有些是轻量级的,像Smart Persist Layer等,只不过,与Nhibernate比起来,仍相去甚远罢了.另外,闲话一句,一直以来,JAVA和.NET两大阵营都互相鄙视,我觉得实属不该,因为Nhibernate就是一个很好的例子.互相吸收这才最重要.Java的长处正是.NET的不足,.NET的优势保尝不是.NET的短处呢?以前很多JAVA们,笑话.NET程序员,有一个很重要的原因就是像有些老鸟网友说的那样:JAVA下的各种框架随手拈来都是威力无经,像Hibernate,像Spring,可是,.NET就太少这方面的东西,MS划了个美好的蓝图,可是蓝力上的建筑太少了,因此,还需要向JAVA学习借鉴.就算如Nhibernate般移植过来,也不失为一种进步.
同时也要说明一下的是NHibernate不是一个软件,很多人误会,以为它是一个类似MyGenerator似的代码生成工具,其实不是,它是一个持久化框架.很多初学者听到框架会犯晕,框架就是为解决某种问题,或某个场景而提出的解决方案,你可以这样理解它,能称的上框加的,一定是完整的解决了某一方面的事务.当然,也有轻量级和重量级之分了.
因此,一个完整的使用NHibernate的项目,实际上可以分成以下几部分:
NHibernate
业务对象
业务对象映射配置
其他业务操作类
NHibernate配置
数据实体
而Nhibernate的原理就是读取配置文件,连接到对应的数据库,根据业务对象以及业务对象映射配置,将业务对象转换成数据实体并保存
需要说明的是:
1,数据源(就是数据实体的管理者)是可配置的,目前NHIBERNATE支持ORACLE,SQL SERVER,MYSQL SERVER,FIREBIRD等,算是十分强大了吧
2,不是说用了NHIBERNATE就抛弃了ADO.NET等,NHibernate仍然支持你使用它们来访问实体对象
好了,到此为止,算是个引子吧,写给那些尚对ORM和NHIBERNATE比较陌生的朋友