一个NHibernate的BUG
来源:互联网 发布:软件上市公司排名 编辑:程序博客网 时间:2024/06/11 14:00
一、背景
我们现在做的项目,用NHibernate实现数据访问层。
访问数据时,有的数据库表是确定的:有明确的表名、字段名。这时候按照常规的方法处理即可:建立数据库表到类的映射,使用HQL读写数据库。
但有的数据访问,所针对的数据库表是不确定的,在运行阶段确定访问哪些数据库表的哪些字段。数据库表和字段都不确定,自然没办法建议O-R映射,只好构造SQL语句了。
既然已经用了NHibernate,我们利用SQL访问数据库时,也仍然使用NHibernate。主要是想利用它管理的Session,还有对分页查询的支持:可以指定开始行,还有所需要的总行数。
就因为贪这个便宜,出问题了。
二、错误
使用SQL(而不是HQL)访问数据库,而且加上访问范围(开始行或总行数),有时候会出现奇怪的问题:有的字段,在数据库中明明有值,但就是读不出来。
例如,有一个数据库表,表的定义大致是:MyTable(Id, Name, FromPoint)。
现在需要查询其中的前10条记录,利用下面的SQL语句:
select Id, Name, FromPoint from MyTable
创建好SQL查询后,设置查询范围:
...var query = session.CreateSQLQuery(sql);query.SetFirstResult(0);query.SetMaxResults(10);...
对于执行结果,期望的是,每条记录有三个字段。但实际上,只返回前两个字段的值,第三个字段,FromPoint的值,没有返回。
查看NHibernate的日志,所生成的SQL是:
select Id, Name from (select Id, Name, FromPoint from MyTable) where rownum<=10
这实在令人费解。
三、原因
在网上搜索,找不到原因。只好祭出最后的杀手锏:跟踪源代码。
结论是:NHibernate在解析SQL语句时有问题,导致过滤掉了不该过滤掉的列。
具体地说,在类 NHibernate.Dialect.Dialect的方法 ExtractColumnOrAliasNames 中有如下代码:
if (token.StartsWithCaseInsensitive("select"))continue;if (token.StartsWithCaseInsensitive("distinct"))continue;if (token.StartsWithCaseInsensitive(","))continue;if (token.StartsWithCaseInsensitive("from"))break;
这段代码的本意,是不将select、distinct等SQL保留字作为列,而且一旦遇到from保留字,就意味着列结束。
问题在于,它用了StartsWith,而不是整词判断,从而误伤了以这些关键字开头的字段。而且一旦有以from开始的字段,后面的字段都被过滤掉了。
四、办法
出问题的方法 ExtractColumnOrAliasNames 是 static internal 的,没有修改机会。我们只好绕道走:自行加上rownum的过滤条件。
本来要借助NHibernate实现跨数据库,我还一直告诫小伙伴们避免使用Oracle、SQL Server等数据库管理系统特定的SQL语法来着。
不少程序员会本能地想到一个解决方法:既然是开源的,而且错误原因找到了,拿过来修改好,编译一个新版本用就OK。我对此明确表示不赞成,一方面,这会脱离NHibernate主线版本的发展,另一方面,也给组件的引用带来不便:我们正在用Spring.NET管理NHibernate,build一个自己的版本,要设置一堆元信息,想想就头大。
五、范围
就我目前所知,该BUG出现的情景如下:
- 使用原生SQL访问数据库;
- 设置了FirstResult、MaxResults等查询结果范围;
- 最早的引入版本不详,最新的版本中,从源代码上判断,此问题仍然存在;
- 我们使用的是Oracle数据库,其它数据库管理系统不详。
- 一个NHibernate的BUG
- 一个NHibernate的介绍
- NHibernate 的bug汇总 ipower.net.cn
- NHibernate的一个小问题
- 一个简单的NHibernate例子
- 一个CodeSmith+NHibernate的例子
- Nhibernate一个错误的解决
- NHibernate一个完整的例子
- nhibernate 的一个小例子
- Nhibernate的一个例子的修正版本
- 自己写的一个NHibernate的工具
- 一个NHibernate的好工具---Query Analyzer
- 总结一个NHibernate的开发小例子
- 自已动手做一个最简版的Nhibernate
- 微软的一个bug?
- OracleParameter 的一个bug
- FireFox的一个bug
- 微软的一个BUG
- HDUOJ - 2048 神、上帝以及老天爷
- 最短路径
- jquery html5 file 上传图片显示图片
- 游标--数据库
- JAVA PriorityQueue 的那些事
- 一个NHibernate的BUG
- GUI层自动化测试不再辉煌
- OnClickListener的不同用法
- 优先队列priority_queue 用法详解
- Android TransitionDrawable ImageView过度效果使用实例
- C++中指针的new和delete
- Masonry介绍与使用实践:快速上手Autolayout
- php在linux中可能用到的命令
- 带外数据