关于 c#:NHibernate 聚合子查询

NHibernate Aggregate Subquery

我对 NHibernate 有一个问题,我似乎无法找到简单的解决方法。

我有以下数据库:

游戏:ID、分数、Match_ID

匹配:ID

一场比赛由三场比赛组成。

我想知道最大匹配分数是多少,所以下面的 SQL 可以解决问题:

1
2
3
4
5
select max(a.total) from
  (select Match.ID, sum(Game.Score) as total
     from Game inner join Match
     on Game.Match_ID = Match.ID
     group by Match.ID) a

在 NHibernate 中,这似乎有点棘手。显然,HQL 不允许 from 子句中的子查询,所以我不能真正使用它。

我很确定它可以用 ICriteria 完成,但我才刚刚开始使用 NH,所以我似乎无法弄清楚。我基本上有以下几点:

1
2
3
4
Session.CreateCriteria<Game>()
    .SetProjection(Projections.ProjectionList()
        .Add(Projections.GroupProperty("Match"))
        .Add(Projections.Sum("Score"))).List();

在那之后,我玩弄了各种各样的 DetachedCriteria,但似乎只是在兜圈子。


对于 HQL 世界,一个查询就可以解决问题...

1
2
3
4
5
6
var maxScore = session.CreateQuery(@"select sum(game.Score)
                                     from Game game
                                     group by game.Match
                                     order by sum(game.Score) desc"
)
                      .SetMaxResults(1)
                      .UniqueResult<long>();

希望这有帮助..

更新:对于 Criteria 世界,可能会有更好的结果转换,但这很有效 :)

1
2
3
4
5
6
7
8
var max = (int)session.CreateCriteria<Game>("game")
    .SetProjection(Projections.ProjectionList()
                       .Add(Projections.GroupProperty("game.Match"))
                       .Add(Projections.Sum("game.Score"),"total"))
    .AddOrder(Order.Desc("total"))
    .SetMaxResults(1)
    .SetResultTransformer(Transformers.AliasToEntityMap)
    .UniqueResult<IDictionary>()["total"];

我实际上会在 SQL 中这样做:

1
2
3
4
select top 1 Match.ID, sum(Game.Score) as total
     from Game inner join Match
     on Game.Match_ID = Match.ID
     group by Match.ID order by total desc

group by 在 Criteria/HQL 中总是很棘手:因为 group by 子句只能返回分组列和任何其他列的聚合。因此,不可能从 group by 子句返回整个实体,只能返回您分组和聚合的 ID。

出于这个原因,我通常使用这样的原生 SQL 对查询进行分组:

1
2
3
4
5
ISQLQuery sqlQuery1 = NHibernateSessionManager.Instance.GetSession().CreateSQLQuery("select Match.ID, sum(Game.Score) as total from Game inner join Match on Game.Match_ID = Match.ID group by match.ID order by total desc");
sqlQuery1.AddScalar("id", NHibernateUtil.Int32); //
sqlQuery1.AddScalar("total", NHibernateUtil.Int32);
sqlQuery1.SetMaxResults(1);    
var result = sqlQuery1.List();