NHibernate 还有哪些不足? 在这篇讨论中组长和园友提了一些当前NHibernate的不足我的补充是1. NHibernate不支持from子句的子查询(subquery)from子句中的子查询又称谓derived table派生表SQL的写法大家都应该比较熟悉举个最简单的例子这里只说明from子查询的形式select Id from(select Id, Name from TableA group by Id, Name)as D;from子句的子查询使用方便、功能强大经常应用于较复杂的查询场景。可惜的是目前最新版本的NHibernate2.1还不支持这种形式的子查询当然了你写包含from子查询的native sql让NHibernate执行的除外将来的版本应该会支持。这里要说一下的是NHibernate是支持where子句的子查询(关联、非关联子查询)的具体见在线帮助文档11.11. Subqueries。2. 不支持select子查询select子查询的SQL写法select Employee.Id, Employee.Name,(select Department.Name from Department where Employee.DepartmentIdDepartment.Id) as DepNamefrom Employeewhere Employee.Id10;查了在线帮助文档和网上资料NHibernate好像是不直接支持这种子查询的。但是可以在mapping文件中将子查询的列映射成property或者使用Criteria的Projections.SqlProjection来实现类似功能。当然了这类子查询我们往往可以使用joininner join或者outer join来实现同样的功能。3.NHibernate2.0的Criteria不支持having子句我们经常需要对数据进行分组统计group by 聚集函数然后再对统计结果进行筛选应用having子句。NHibernate2.0的HQL支持having子句但是NHibernate2.0的Criteria却不支持having子句经过测试可以调用相关API但是执行没有效果。因此如果要在NHibernate2.0中使用having子句就必须得使用HQL而不能使用Criteria可我是一直比较喜欢使用Criteria的实在比较郁闷……我为什么喜欢使用Criteria也就是说Criteria与HQL相比有哪些优点在以后的文章中再和大家详细讨论。值得庆幸的是根据最新的NHibernate2.1的发布文档说明解压NHibernate2.1后便可看到releasenotes.txt文件其中有一条Patch * [NH-1280] - Adds HAVING support to CreateCriteria queries, Fixes parameter order bugsCriteria可以支持having不过我还没试过具体的使用可以参见该文Adds HAVING support to CreateCriteria queries, Fixes parameter order bugs。4.不支持Property级别的lazy load目前只支持关联实体或者关联集合的延迟加载不支持更细粒度的Property级别的延迟加载而Linq to sql支持Property级别的延迟加载。二、减少SQL语句的讨论在这篇讨论中大家提出了减少NHibernate查询生成的SQL语句、避免n1问题以提高性能的方法我的看法是1.立即加载(lazyfalse)并不能在所有情况下都会减少SQL语句同时还会带来过量读取数据的严重后果比如在mapping文件中为实体AEntity设置了一个关联实体BEntity并且将这个关联设置为lazyfalse这样当加载实体AEntity时调用Get(id)NHibernate就会自动加载实体BEntity。通过查看NHibernate生成的sql发现NHibernate生成的是2条sql第一条sql获取的是AEntity第二条获取的是BEntity所以说在这种情况下我的理解是lazyfalse并不会减少实际执行的sql语句只是减少了程序员编写查询sql的数量适当减轻了程序员的编程负担。立即加载的最大好处就是关联实体或集合由NHibernate自动加载无需程序员手工加载。但是付出的代价则是有可能导致数据的过量读取加大数据库、网络数据传输、应用服务器的负担举例如下1多对一的关联实体立即加载比如当前某个操作仅需获取AEntity而不需要获取BEntity的详细信息由于立即加载导致在加载AEntity的同时加载BEntity如果BEntity还关联了CEntity而且也是立即加载那么NHibernate同时还会加载CEntity如果CEntity还关联了……2一对多的关联集合立即加载如果关联的数据是一个集合并且集合数据很多比如集合中有成千上万条数据那么一次性立即加载整个关联集合数据的开销是显而易见的。3类class级别的lazyfalse上面提到的两种情况是把lazyfalse设置在关联级别上细粒度如果把lazyfalse设置在整个class上大粒度那么情况将更加糟糕这样当加载该类实体时会同时加载所有关联的实体和集合。2.所有的关联实体和关联集合最好都保持默认的延迟加载由上面的分析可知关联实体和集合最好保持默认的延迟加载所以我在实际的开发中是不进行任何lazyfalse设置的。如果要同时加载关联实体或集合最有效的方法就是编写join和 dynamic fetching join的查询操作这既可以减少所需执行的sql语句join操作可以在一条语句中获取多个关联实体关联数据表或关联实体的properties字段 这是由join这类关系操作的本质决定的同时按需获取数据避免数据的过量加载。3. 普通join与 dynamic fetching join的区别刚开始使用NHibernate时以为join与 dynamic fetching join是一回事后来才明白两者的区别。我的理解说得简单一点就是dynamic fetching join会在一条sql语句中获取关联实体和/或关联集合数据并把它们装配marshal成完整的persistent entity。而join会在一条sql语句中可以仅获取关联实体的某个property或某几个properties而不一定是一个完整的persistent entity。具体join与 dynamic fetching join操作请参见在线文档。4. 尽量避免在mapping文件中进行如下这些设置如lazyfalse(立即加载), fetchsubselect子查询抓取batch-size20批量抓取fetchjoin关联抓取等因为在 mapping文件中的设置是global设置会对整个系统产生全局性的影响。而且有些设置对Get、Load、HQL和Criteria都产生影响而有些设置对HQL不影响对Criteria有影响。举个例子当分别执行同样功能的HQL和Criteria时却得到不同的查询结果时你或许会感到非常惊讶当对此问题进行了一天一夜的调试和冥思苦想之后突然发现是由于mapping文件中的某个设置导致HQL和Criteria的差异时你一定会气得想把电脑给砸了并发誓永不再在mapping中设置这些东西5.使用NHibernate二级缓存是最好的选择吗使用NHIbernate二级缓存的缺点如下1二级缓存机制透明得让人觉得不可控2增加了测试、调试的复杂性3如果使用BULK或native sql对数据直接进行CUD操作NHibernate是不会自动更新二级缓存的导致二级缓存数据stale。为了避免stale必须手工更新或同步缓存。我的建议是使用spring.net的缓存在Service层(或BLL层)进行实体和查询结果数据的缓存好处如下1spring.net的缓存既强大又灵活可配。2如果系统有一天NHibernate被ADO.net、EF、linq to sql等其他机制替换了尽管这种替换的可能性不大spring.net缓存不受任何影响。3不在DAL层而在service层或BLL层做缓存使得DAL层的测试变得简单。6.NHibernateSpring.NetNHibernate再结合Spring.Net省下大把大把的开发、维护时间请给我一个不NHibernateSpring.Net的理由7.只可惜.NET阵营中使用这两个优秀框架的人不多在国内外相关论坛问个问题答的人太少了。今年算是有了第一本关于Nhibernate的书籍《NHibernate in action》Spring.net到目前为止还没看到任何书籍而在线文档又极其简陋。