NHibernate标准查询问题

时间:2009-11-24 14:09:56

标签: nhibernate

我有3个相关对象(Entry,GamePlay,Prize),我正在尝试找到使用NHibernate查询我需要的最佳方法。当请求进入时,我需要在条目表中查询匹配的条目,如果找到,则获得a)最新的游戏以及附有奖品的第一个游戏。 Prize是GamePlay的子项,每个Entry对象都有一个GamePlays属性(IList)。

目前,我正在开发一种拉动匹配条目并急切加载所有游戏和相关奖品的方法,但加载所有游戏只是为了找到最新的游戏和任何包含奖品的游戏。 / p>

现在,我的查询如下:

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. 每个游戏都没有急切地加载Prize子属性。因此,我遍历GamePlays列表寻找非空奖品的代码必须调用加载我检查的每个奖品属性。<​​/ li>

    我不是一个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,不要使用它)。

1 个答案:

答案 0 :(得分:0)

因为你在每个请求中都这样做,所以在你的实体中设置两个公式属性应该更好。 第一个应该获取最新的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获取游戏玩法

或者,您可以使用过滤器进行解决。 将集合设置回“懒惰” 并创建这些漂亮的过滤器

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命中:一个用于原始Entry,一个用于多个查询。

最后但并非最不重要的是,您可以在Entry实体中定义2个行李,一个IList<GamePlay> Latest和一个IList<Gameplay> WinnerEntry映射文件中的行包将被过滤适当的查询(虽然我现在不记得你是否可以在过滤器中定义TOP子句)并将它们设置为非惰性。然后通过单次往返,您可以使用以下(丑陋)语法

获得所需的所有数据
Entry entry = findEntry(phoneNumber);
Gameplay winner = entry.Winner[0]; //check this if null first
Gameplay Latest = entry.Latest[0]; //ditto

请注意,在所有解决方案中,第3个是提供生成其他查询的机制的解决方案,因为可以在Criteria / HQL查询中使用该包