园子里有些人,他们真以为自己明白了面向对象,然后装着满腹经纶,侃侃而谈,一篇接一篇,不厌其烦地喊着ORM如何如何。你以为他真的明白“面向对象”么?其实,他对面向对象的理解仅限于教科书中的封装、继承和多态,或者再知道一点面向对象的若干原则但其实并不真正理解。
笔者愚钝,入行多年尚不懂面向对象,只懂得用其形而不懂用其实。五年后的某一天终于开窍,明白了面向对象之实,也仅仅是一个开始而已。当又经历了另一个五年的倦怠,发现并理解了设计模式、面向方面等技术作为面向对象的必要补充后,才算是彻悟!所以当我见过一个同学,尚未出校门已然彻悟,真是羞愧!
有一天面试的时候,我问一位同学,Framework和Library的区别是什么?他答不上来。而另一个同学略一思考就告诉我,你的程序会调用Library,而Framework会调用你的程序。虽然精辟,但我还是要补充:Framework通常也会提供一个Library,所以,Library是水平的,而Framework是垂直的,此处的“水平”和“垂直”是相对应用系统的层次设计而言的。如果没有层次,其实Framework其实就是Library。Microsoft的Enterprise Library当然就是一个Library,无法代替Framework。
如果让那位已经彻悟的同学舍弃ORM来实现复杂的业务功能,他当然无法接受。相反,如果让一位抱着《Thinking in Java》似懂非懂的同学用ORM来实现同样的功能,他也一样无法接受。其中的一些同学非常擅于“鸡蛋里挑骨头”,于是园子里有了这样一堆垃圾文章或者垃圾跟贴。另外一些同学不精于这样的能力,所以仍在徬徨之中。
此乃ORM惟一之硬伤也!如果你不理解面向对象思想,就先试着去理解,然后再来讨论ORM这个话题,并发表你的高见。
再说性能
ORM提供了所有SQL语句的生成,代码人员远离了数据库概念。从一个概念需求(例如一个HQL)映射为一个SQL语句,并不需要什么代价,连1%的性能损失都没有。真正的性能损失在映射过程中,更具体地讲,是在对象实例化的过程中。我曾经做过一个试验,以“计算第N个素数”这样的命题。我采用Delphi写Native Win32 Console程序,又采用C#写CLR Console程序。两者相比,令我大失所望。
N |
结果 |
耗时 |
|
Delphi |
C# |
||
1000 |
7927 |
0ms |
2ms |
10000 |
104743 |
16ms |
17ms |
100000 |
1299721 |
438ms |
324ms |
1000000 |
15485867 |
11437ms |
7823ms |
灵活性
ORM不够灵活?我完全不能理解,我甚至不知道这个不够灵活是与什么基准相比。相反,ORM可以让你灵活地替换数据库(当然这个优点并没有非常重要的意义);在修改数据库以后不需要修改服务层或者只需要进行简单的修改;可以对某个服务进行单独的测试;可以对服务进行不依赖数据库的、上下文一级的扩展;可以进行更好的层次设计;......
不能实现所有的查询条件
如果是想表达“每一个Select语句可以通过面向对象的方式进行查询”的话,我觉得目前绝大部分ORM框架都已经很好地解决。我解决这一问题的基础是:我不提供超越SQL ANSI92的能力,但覆盖SQL ANSI92的所有功能。对于解决实际应用中的不足部分,采用运行时算法补充。Hibernate采用的是HQL这样的方式,基本上SQL能够做到的,HQL都无一例外可以做到。ECO采用的是OCL的方式,其功能可以完全覆盖SQL。我的框架所实现的查询目前我还没有发现无法解决并必须利用Native SQL来实现的(因此我无法理解Hibernate3为什么要提供这样的扩展)。Hibernate采用的策略是以面向对象为核心,换句话说,以持久化对象为终极目标,而以加载对象以持久化对象为前提。设计一个POJO,实例化,然后保存起来,下次使用的时候可以依样载入即可。大规模的查询并不是框架的核心目标。所以,如果你完全依赖Hibernate去持久化,我非常担心你将来是否有机会用你的数据积累去做数据仓库。而我的框架目标则不同。在持久化与加载两个目标间我没有主次之分。我也没有超前到MDA,我的对象模型仍然基于数据库的ER设计,我仍然提供一组非常清晰明了的数据库视图。
多表连接查询
如果需要将多表的连接查询结果转换成一个二维视图,显然需要你再定义另一个视图实体对象,将视图映射到对象模型。如果你仅仅是要在一个对象实例的某个属性中获得另外一个对象的集合,似乎这不是DAL方式的优势,而反而是ORM的优势。将多个对象所依赖的多个对象放到同一个上下文中,显然这是最好的一种方式。
统计查询
从理论上讲,ORM不适合做OLAP,不适合做太多统计查询。其实这一点,我的框架已经提供了非常好的解决方案,对Aggregate到面向对象的视图处理得非常好。
开发效率
提高开发效率仅仅是一个抽象的目标,具体的手段应该是两个方面:一是IDE和辅助工具;一是适合将任务分解成多个解耦的部分从而可以通过增加人员来提升总的开发效率。虽然ORM仅仅是开发环节中很小的一部分,但是却遍布应用系统中的每一角落,因而对开发效率影响较大。除了ORM,难道还有更好的选择么?
ORM后,原来精湛的SQL技能变得毫无用武之地,让人甚是失落,但这并不是ORM的过错。