上次贴出来的那个ORMBattle,我也说过了,喷的人很多。其中相当一部分是NH的爱好者或者开发者,主要内容就是性能测试中NH没有做优化,双方互发了好多博文,到最后Fabio Maulo已经开始说一些不好听的了,而且还“抱歉这篇我不用英语了”然后就开始用西班牙语喷= =(感谢google translator。。。)
当年(09年)几乎同一时期,又有一哥们进行了EF vs NH的性能测试。结果类似,NH惨败。NH大牛们于是又站出来喷,哥们赶紧又发了一篇,包含了大牛们给出的优化方案。其实从图上来看,NH还是败了的,但是哥们还是
很违心的(大雾)
出来搅混水说“性能差不多”,“性能并不是我们的唯一追求”之类的。
从上面这两档子事儿可以看出来,NH在拥有强大扩展能力的同时学习曲线也是比较高的。
还有就是NH大牛们肚量实在是。。。
抱歉这一段我不能用英语(你根本没这个能耐好伐?
于是本文让我们把性能这一篇儿翻过去,只是单纯的看看大家对两个框架的看法。括号中含一些个人吐槽
InfoQ中文版给出了原文大意以及一些精彩吐槽的翻译。
我只能说NH大牛果然又不淡定了。InfoQ英文版里也有一些不错的吐槽,从技术到项目本身。从总体上来讲这些吐槽是倾向于支持NH的,但是也有一些犀利的观点认为NH没有公司支持,早晚会被EF超越。注意当时NH3和EF4.1都还未发布,一些观点可能已经不适用。摘抄一些如下:大牛的观点是:
NH支持
- 批量写入
- 批量读/多重查询特性(我理解是在说Future?)
- 批量的集合加载
- 带有lazy="extra"的集合
- 集合过滤器和分页集合
- 二级缓存(实际上NH的二级缓存貌似也很简单?)
- 调整
- 集成和扩展性
EF的优点在于
- Linq(NH3.0的Linq支持有不错的进展)
- EF属于微软
一些吐槽:
- NH的错误信息太差(这个确实。感觉上你想明白NH的异常在说什么就要理解它的实现机制,也许读过《企业应用架构模式》会好一些?)
- EF的文档更好(NH的文档真的狠orz,很多照抄了java版的不说,连实际上存在的feature都没有介绍。。。),但是NH的社区支持更多(其实NH的问题确实能一搜结果一堆,但是很多都帮助有限。。。。。。)
- EF支持变更跟踪
- NH更好的支持UT
- EF有很好的设计器
- 设计器神马的都是歪门邪道,微软的强类型DataSet也有设计器还不是渣(DataSet躺着也中枪啊。。。)
- NH的一个很大缺陷是不能load部分的对象图(我理解这个意思是说EF有include?NH也能fetch啊?)。NH的懒加载也许是一个解决方案但一般只能支持两层模型(App+DB)而EF支持n层模型
- NH的Iesi.Collections在WCF的序列化中有问题,而且ISet没有indexer(ISet为啥要有indexer啊。。。要indexer就用IList好了么。。。话说NH啥时候完全迁移到.Net4就能抛弃Iesi.Collections了)
- 还是加载对象图的问题。EF有能力在一个Query中完成(但是也有人说这个Query的性能很差,比如说很多column都是重复数据),而NH连在一次数据库访问中完成都做不到,不论我用Fetch还是Future。
- NH的学习曲线陡。IDE支持也不好,除了NH本身可能还需要熟悉一些其他的OSS
- NH没有投资人。也就是说bug fix速度,新版本开发速度等等都得不到保障。
在stack overlow上,EF vs NH是一个常被问及的问题。总体上来讲,因为该站NH经验丰富的人比较多,多以NH的好话比较多。在EF的早期年代,喷EF不支持POCO的人是超多的,直到最近也有人狂喷EF称其比起NH还处在石器时代。不过比较平和的说法是EF比起NH在扩展性上差太多。(这一段不是翻译完全是我的吐槽)
之后网上也有很多blog post。可以选择性的看看,其实喷的内容大同小异。注意不要看太老的,对EF不公平(虽然NH3也出了,但是相关的对比文章太少了没办法)。推荐Dino Esposito的一个系列文章。这个系列从多数据库支持、懒加载、Fetch、二级缓存、Self-tracking entities、Queries六个方面进行了比较。从基调上,Dino Esposito是给微软写书的,说EF好话多一些。。。另外这个系列比较新,写的时候NH3都快出了。
这个问题有两个内容:一是支持多种数据库,二是同一Application内同时使用多个数据库。对于前者作者含蓄的支出了EF需要第三方支持。后者的问题上二者都有解决办法。
EF只能支持对navigation property的懒加载。而且是context范围的,runtime控制。(不过后面作者又补了一句说如果使用POCO model,使用proxy,virtual property都可以懒加载。。。不知道哪个对。。。)
NH通过配置实现懒加载,可以精确到property级别。但是不知道能不能runtime控制。
EF的Fetch是通过runtime调用Include方法。实现上基本上是翻译成一个OUTER JOIN
NH的Fetch是通过SetFetchMode实现(这里我插一句,作者这里讲的是用Criteria API的方式,用HQL的话可以直接写fetch,用Linq的话还没试过。。。)。有JOIN和SELECT两种mode。后者是通过另一个SELECT实现,默认懒加载,除非强制关掉了懒加载。另外配置文件里也可以写fetch mode,例如指定一个one-to-many的fetch mode
虽然跟Fetch不直接相关,还是讲一下NH的multi-query和Future。前者是一次执行多个query(作者这里的例子还是使用Criteria API,HQL的话可以直接写多个query,Linq的话不知。。。)。后者是真正访问数据的时候才执行SQL(不知道NH3.0的Linq实现没有,反正2.1.2时根本没实现Future方法)
EF不内建二级缓存。可以通过实现一个ProviderFactory来插入自己的二级缓存管理。
NH内建了一些二级缓存的provider,也有第三方实现。NH会缓存三种东西:entities、queries、timestamps。配置上和runtime可以控制是否使用cache。注意NH的二级缓存的生命周期是跟着SessionFactory走的。
EF独家支持Self-tracking。编辑器会为你实现IObjectWithChangeTracker(这种模型也好意思叫POCO。。。作者也介绍了一种更POCO的办法,让本应属于DAL的这部分逻辑分离,看得我很orz)
NH可以使用SaveOrUpdateCopy方法,但是实际上是一个两步操作,而不像EF一样是一步操作。(在NH3.1中这个方法已经被标记为Obsolete,请改用Merge。而且NH的级联设置里为啥没有merge这个选项乜?)
EF支持两种检索方式:Entity SQL Language(相当于NH中的HQL,不过不知能力如何)和普通的Linq to Entities。另外,也可以使用precompiled表达式。
NH支持Criteria API,HQL,Linq(2.x时代是基于Criteria,3.0之后基于HQL),QueryOver(Criteria的包装)(实际上好像NH3支持7中query方式?)另外提一句multi-queries和Future。