一個NHibernate的BUG,NHibernateBUG

來源:互聯網
上載者:User

一個NHibernate的BUG,NHibernateBUG
一、背景

我們現在做的項目,用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出現的情景如下:



相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.