2012-05-23 10 views
2

我看到我所說的錯誤NHibernate的與查詢緩存和ORDER BY子句...NHibernate的檢索,即使ORDER BY子句不同

當我運行下面的查詢緩存的查詢結果...

SELECT this_.Id   as y0_, 
     this_.Name  as y1_ 
FROM Products this_ 
WHERE this_.IsActive = 1 
ORDER BY this_.IsPremium desc 

... NHibernate的成功緩存它的結果,如果我有查詢緩存打開,我告訴它緩存此查詢(例如,使用criteria.SetCacheable(true))。

不幸的是,精彩的NHProf告訴我,NHibernate的運行此查詢時使用緩存的查詢結果也:

SELECT this_.Id   as y0_, 
     this_.Name  as y1_ 
FROM Products this_ 
WHERE this_.IsActive = 1 
ORDER BY this_.IsPremium desc, 
     this_.Name 

任何人能解釋爲什麼或點我到一些深層次的文檔這個「功能」 ?或者,甚至更好,有沒有人有解決方案的問題?

+0

SetCachable用於二級緩存目的。你在使用二級緩存嗎?我的猜測是你只使用一級緩存,由一個身份地圖實現。 – TedOnTheNet

回答

0

NHibernate使用第一級緩存(由身份映射實現)來緩存您查詢的每個對象。即使查詢對象列表,NHibernate也可以處理單個實體。

讓我解釋一些東西:
您查詢,如果你執行這個查詢,並得到實體ID爲1:

session.get<SomeEntity>(1); 

的NHibernate將檢查高速緩存,看看它是否包含ID 1了。如果是這樣,緩存的對象將被返回並且不會運行查詢。如果不是,則執行查詢選擇記錄,將其放入緩存並將其返回給您。如果再次執行該查詢,它將被緩存,並且該對象將在沒有新查詢的情況下返回。

現在,如果查詢像這樣的列表:

session.QueryOver<SomeEntity>().List(); 

NHibernate的不知道哪個ID的將是牽強,因此它會查詢所有的記錄和核對緩存結果一個接一個,即使您運行查詢兩次。假設你的數據庫中有2條記錄(id 1和2)。您的緩存仍然爲空時,您可以使用查詢獲取它們。這兩個記錄都被提取,放入緩存並返回給您。現在你插入記錄3,4和5,而你在它的時候,你也會更新記錄1。現在,如果再次運行查詢,它將讀取所有5條記錄,但現在也緩存記錄3,4和5。您將得到一個包含5個對象的列表,其中3,4,5是剛剛讀取的對象,但返回1和2的緩存版本。你不會得到更新版本的ID 1.

因此回答你的問題:改變順序無關緊要。您的查詢將產生一組逐條檢查緩存的記錄,如果其中一個已經存在,則返回此緩存版本。

解決你的問題可能是:使用session.Refresh

  • (OBJ);如果你知道哪些更新了。
  • 驅逐會話中的部分或全部實體(這意味着它們將被拋出緩存並可通過查詢重新獲取)。注意:如果你驅逐他們,更改將不會被保存。
  • 您可以使用無狀態會話,它具有 - 如無狀態名稱所示 - 無緩存。