目录
一、背景
二、错误
三、原因
四、办法
五、范围
首页 数据库 mysql教程 一个NHibernate的BUG

一个NHibernate的BUG

Jun 07, 2016 pm 04:12 PM
bug 我们 背景 项目

一、背景 我们现在做的项目,用NHibernate实现数据访问层。 访问数据时,有的数据库表是确定的:有明确的表名、字段名。这时候按照常规的方法处理即可:建立数据库表到类的映射,使用HQL读写数据库。 但有的数据访问,所针对的数据库表是不确定的,在运行阶

一、背景

我们现在做的项目,用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数据库,其它数据库管理系统不详。 
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门文章

仓库:如何复兴队友
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.能量晶体解释及其做什么(黄色晶体)
1 周前 By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒险:如何获得巨型种子
3 周前 By 尊渡假赌尊渡假赌尊渡假赌

热门文章

仓库:如何复兴队友
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.能量晶体解释及其做什么(黄色晶体)
1 周前 By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒险:如何获得巨型种子
3 周前 By 尊渡假赌尊渡假赌尊渡假赌

热门文章标签

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

AI攻克费马大定理?数学家放弃5年职业生涯,将100页证明变代码 AI攻克费马大定理?数学家放弃5年职业生涯,将100页证明变代码 Apr 09, 2024 pm 03:20 PM

AI攻克费马大定理?数学家放弃5年职业生涯,将100页证明变代码

深入了解PyCharm:快速删除项目的方法 深入了解PyCharm:快速删除项目的方法 Feb 26, 2024 pm 04:21 PM

深入了解PyCharm:快速删除项目的方法

分享PyCharm项目打包的简易方法 分享PyCharm项目打包的简易方法 Dec 30, 2023 am 09:34 AM

分享PyCharm项目打包的简易方法

PyCharm实用技巧:将项目转换为可执行EXE文件 PyCharm实用技巧:将项目转换为可执行EXE文件 Feb 23, 2024 am 09:33 AM

PyCharm实用技巧:将项目转换为可执行EXE文件

游戏bug是什么意思 游戏bug是什么意思 Feb 18, 2024 am 11:30 AM

游戏bug是什么意思

制作 iPhone 上 iOS 17 提醒应用程序中的购物清单的方法 制作 iPhone 上 iOS 17 提醒应用程序中的购物清单的方法 Sep 21, 2023 pm 06:41 PM

制作 iPhone 上 iOS 17 提醒应用程序中的购物清单的方法

win7系统登陆时的默认图片背景如何更改 win7系统登陆时的默认图片背景如何更改 Jun 30, 2023 pm 04:03 PM

win7系统登陆时的默认图片背景如何更改

Win11 新版画图:一键移除背景实现抠图功能 Win11 新版画图:一键移除背景实现抠图功能 Sep 15, 2023 pm 10:53 PM

Win11 新版画图:一键移除背景实现抠图功能

See all articles