2009-11-24 97 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查询