2009-11-24 102 views
0

我有3個相關的對象(Entry,GamePlay,Prize),我試圖找到最好的方式來查詢他們爲我需要使用NHibernate。當有請求進入時,我需要在Entries表中查詢匹配的條目,並且如果找到的話,可以得到a)最新的遊戲以及附帶獎品的第一場遊戲。獎品是GamePlay的子項,每個Entry對象都有一個GamePlays屬性(IList)。NHibernate標準查詢問題

目前,我正在研究一種方法來拉取匹配的條目,並熱切地加載所有遊戲和相關獎品,但加載所有遊戲只是爲了找到最新的遊戲以及任何包含獎品的遊戲似乎是浪費。

現在,我的查詢看起來是這樣的:

var entry = session.CreateCriteria<Entry>() 
    .Add(Restrictions.Eq("Phone", phone)) 
    .AddOrder(Order.Desc("Created")) 
    .SetFetchMode("GamePlays", FetchMode.Join) 
    .SetMaxResults(1).UniqueResult<Entry>(); 

兩個問題:

  1. 它加載所有的遊戲玩了前面。利用365天的數據,這可以輕鬆地將每個查詢的數據擴展到300k。
  2. 它並不急於加載每個遊戲的獎品屬性。因此,我通過GamePlays列表尋找非空獎的代碼必須進行調用才能加載我檢查的每個Prize屬性。

我不是一個nhibernate專家,但我知道必須有一個更好的方法來做到這一點。理想情況下,我想這樣做以下(僞):

entry = findEntry(phoneNumber) 
lastPlay = getLatestGamePlay(Entry) 
firstWinningPlay = getFirstWinningGamePlay(Entry) 

當然,最終的結果是,我有條目的詳細信息,最新的遊戲,和第一個贏取的遊戲。問題是我想盡可能少地調用數據庫,否則我只執行3個單獨的查詢。

對象定義是這樣的:

public class Entry 
{ 
    public Guid Id {get;set;} 
    public string Phone {get;set;} 
    public IList<GamePlay> GamePlays {get;set;} 
    // ... other properties 
} 

public class GamePlay 
{ 
    public Guid Id {get;set;} 
    public Entry Entry {get;set;} 
    public Prize Prize {get;set;} 
    // ... other properties 
} 

public class Prize 
{ 
    public Guid Id {get;set;} 
    // ... other properties 
} 

正確的NHibernate的映射到位,所以我只需要幫助搞清楚如何設置的條件查詢(不找HQL,不使用它)。

+0

HQl比標準更強大。標準適用於動態查詢,HQL適用於複雜的查詢。 HQL還有其他的好處,例如你可以將它們存儲在預編譯的映射文件中。 – 2009-11-24 14:38:13

+0

是的,HQL功能更強大,但它聽起來像用戶想堅持直接標準。我可以挖掘它。 – 2009-11-24 15:17:49

+0

@Chris:嘗試用SQL思考。你會發出什麼樣的詢問以最佳方式獲取數據?您可以使用3個帶小結果集的查詢或帶有大結果集的查詢。請記住,NHibernate只能生成SQL,它不能以任何其他方式從數據庫中獲取內容。 – 2009-11-24 15:28:53

回答

0

因爲您在每個請求中都這樣做,所以最好在實體中設置兩個公式屬性。 第一個應該有一個NOT NULL屬性獲取最新的遊戲-ID和其他第一遊戲-ID

這可能是因爲這樣在Entry

<property name="LatestGameplay" formula="select top(1)gp.Id from Gameplay gp where gp.FK_EntryId = PK_EntryId order by gp.InsertDate desc" /> 

XML映射文件

這會讓你在Entry實體上留下游戲玩法Id,並且在你獲取它之後,它需要再次往返DB去GetById - 獲取遊戲玩法

或者你可以工作nd使用過​​濾器。 將收集回「懶人」 和創建這些漂亮的過濾器

Gameplay latest = NHibernateSession.CreateFilter(entry.GamePlays , "order by InsertDate desc").SetMaxResults(1).SetFirstResult(1).UniqueResult<Gameplay>(); 

Gameplay winner = NHibernateSession.CreateFilter(entry.GamePlays , "where FK_PrizeId is not null order by InsertDate asc ").SetMaxResults(1).SetFirstResult(1).UniqueResult<Gameplay>(); 

而且IFilter的可以在multiquery被用作這樣有2分貝命中:一個原始Entry,一個用於multiquery。

最後但並非最不重要的,你可以定義2袋在Entry實體,一個IList<GamePlay> Latest和一個IList<Gameplay> Winner這在Entry映射文件會以適當的查詢過濾(雖然我現在不記得,如果你可以定義TOP過濾器中的子句)並將其設置爲非惰性。然後用單次往返,你可以擁有所有的數據要與以下(醜)語法

Entry entry = findEntry(phoneNumber); 
Gameplay winner = entry.Winner[0]; //check this if null first 
Gameplay Latest = entry.Latest[0]; //ditto 

注意,所有解決方案的第3個是提供一種機制來產生額外的查詢之一,該包可用於標準/ HQL查詢