一個NHibernate的BUG

來源:互聯網
上載者:User

標籤:str   而不是   from   資料庫管理   語句   指定   階段   編譯   column   

一、背景

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

  1. 使用原生SQL訪問資料庫;
  2. 設定了FirstResult、MaxResults等查詢結果範圍;
  3. 最早的引入版本號碼不詳,最新的版本號碼中。從源碼上推斷。此問題仍然存在。
  4. 我們使用的是Oracle資料庫,其他資料庫管理系統不詳。

??

一個NHibernate的BUG

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

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.