簡體   English   中英

NHibernate標准查詢問題

[英]NHibernate criteria query question

我有3個相關的對象(參賽,游戲,獎品),並且我試圖找到使用NHibernate查詢它們的最佳方法。 收到請求時,我需要在Entries表中查詢匹配的條目,如果找到,則獲得a)最新的游戲以及附帶獎勵的第一個游戲。 獎品是GamePlay的子級,每個Entry對象都有一個GamePlays屬性(IList)。

當前,我正在研究一種方法,該方法可以提取匹配的Entry並熱切地加載所有游戲和相關獎品,但是加載所有游戲只是為了查找最新的游戲以及包含獎品的游戲似乎很浪費。

現在,我的查詢如下所示:

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列表中循環查找非空獎品的代碼必須調用以加載我檢查的每個獎品屬性。

我不是專家,但是我知道必須有更好的方法來做到這一點。 理想情況下,我想執行以下操作(偽代碼):

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,請勿使用它)。

因為您在每個請求中都這樣做,所以最好在您的實體中設置兩個公式屬性。 第一個應獲取最新的Gameplay-Id,另一個應獲取不具有Null屬性的第一個Gameplay-Id

Entry的xml映射文件中可能就是這樣

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

這會為您留下Entry實體上的游戲ID,在您獲取它之后,它需要再次往返數據庫才能獲取GetById,從而獲取游戲的ID。

或者,您可以使用過濾器來解決。 將集合設置回“惰性”並創建這些漂亮的過濾器

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可以在多查詢中使用,因此有2個db hits:一個用於原始Entry ,另一個用於multiquery。

最后但並非最不重要的一點是,您可以在Entry實體中定義2個袋子,一個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

請注意,在所有解決方案中,第三個是提供一種生成附加查詢的機制的解決方案,因為該包可以在Criteria / HQL查詢中使用

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM