一个NHibernate的BUG
一、背景
我们如今做的项目,用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,而不是整词推断。从而误伤了以这些keyword开头的字段。并且一旦有以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的应用配置
NHibernate是.Net平台下一个成熟的,开源的对象关系映射器(ORM).本文来介绍第一次使用NHibernate的时候的配置. 1.下载NHibernate.Nhibernate官网最新版本为 ...
- [转]NHibernate之旅(2):第一个NHibernate程序
本节内容 开始使用NHibernate 1.获取NHibernate 2.建立数据库表 3.创建C#类库项目 4.设计Domain 4-1.设计持久化类 4-2.编写映射文件 5.数据访问层 5-1. ...
- Nhibernate学习教程(2)-- 第一个NHibernate程序
NHibernate之旅(2):第一个NHibernate程序 本节内容 开始使用NHibernate 1.获取NHibernate 2.建立数据库表 3.创建C#类库项目 4.设计Domain 4- ...
- NHibernate从入门到精通系列(3)——第一个NHibernate应用程序
内容摘要 准备工作 开发流程 程序开发 一.准备工作 1.1开发环境 开发工具:VS2008以上,我使用的是VS2010 数据库:任意关系型数据库,我使用的是SQL Server 2005 Expre ...
- 一个iOS6系统bug+一个iOS7系统bug
先看实际工作中遇到的两个bug:(1)iPhone Qzone有一个导航栏背景随着页面滑动而渐变的体验,当页面滑动到一定距离时,会改变导航栏上title文本的颜色,但是有一个莫名其妙的bug,如下:
- FIREDAC(DELPHI10 or 10.1)提交数据给ORACLE数据库的一个不是BUG的BUG
发现FIREDAC(DELPHI10 or 10.1)提交数据给ORACLE数据库的一个不是BUG的BUG,提交的表名大小写是敏感的. 只要有一个表名字母的大小写不匹配,ORACLE就会认为是一个不认 ...
- pycharm下: conda installation is not found ----一个公开的bug的解决方案
pycharm conda installation is not found ----一个公开的bug的解决方案 pycharm+anaconda 是当前的主流的搭建方案,但是常出现上述问题. ...
- 一个神奇的bug:OOM?优雅终止线程?系统内存占用较高?
摘要:该项目是DAYU平台的数据开发(DLF),数据开发中一个重要的功能就是ETL(数据清洗).ETL由源端到目的端,中间的业务逻辑一般由用户自己编写的SQL模板实现,velocity是其中涉及的一种 ...
- salesforce零基础学习(一百一十五)记一个有趣的bug
本篇参考:https://help.salesforce.com/s/articleView?language=en_US&type=1&id=000319486 page layou ...
随机推荐
- 【洛谷3546_BZOJ2803】[POI2012]PRE-Prefixuffix(String Hash)
Problem: 洛谷3546 Analysis: I gave up and saw other's solution when I had nearly thought of the method ...
- “浪潮杯”第九届山东省ACM大学生程序设计竞赛重现赛 C-Cities
题目描述:There are n cities in Byteland, and the ith city has a value ai. The cost of building a bidirec ...
- 338 Counting Bits Bit位计数
给定一个非负整数 num. 对于范围 0 ≤ i ≤ num 中的每个数字 i ,计算其二进制数中的1的数目并将它们作为数组返回.示例:比如给定 num = 5 ,应该返回 [0,1,1,2,1,2] ...
- javascript:void(0);什么意思
js里面void是一个操作符,该操作符计算表达式的值,但是不返回任何内容. <a href="javascript:void(0);"> 这里用到void(0)表示取消 ...
- vue-cli的创建、基本配置和遇到的问题总结
vue-cli的创建及基本配置 1. 创建 vue-cli 项目 确保本地安装了最新版本的nodejs环境(会自带npm环境); 全局安装vue-cli,命令:npm i -g vue-cli 创建项 ...
- Java学习笔记_网络+多线程
支持同时收发的客户端和服务器端 客户端 import javax.swing.*; import java.awt.*; import java.io.*; import java.net.*; im ...
- HTML 网页创建
最简单的方式就是创建一个文本文档,然后将.txt后缀改为.html或者htm. 完成上面的步骤会创建一个完全空白的网页,下面填充一点内容,代码实例如下: <!DOCTYPE html> & ...
- 02--Tomcat总体结构分析一
注:此文章大部分参考大神文档,并且结合自身理解,补充了其他相关知识,谢绝转载. 大神原文地址链接:http://www.ibm.com/developerworks/cn/java/j-lo ...
- html5——多媒体(三)
自定义进度条 1.video标签是内联块,可以设置宽高,但是需要用大盒子将其包裹起来进行定位 2.小盒子设计成进度条样式,并进行定位 3.进度条样式中的特殊按钮可以用web字体 4.通过点击实现视频的 ...
- html5——动画案例(太阳系)
太阳系主要利用定位,伪元素 <!DOCTYPE html> <html lang="en"> <head> <meta charset=& ...