2009-11-04 5 views
2

J'ai un problème avec NHibernate que je ne semble pas être en mesure de trouver un moyen simple.NHibernate Aggregate Sous-requête

J'ai la base de données suivante:

Jeu: ID, Score, Match_ID

Match: ID

Un match se compose de 3 jeux.

Je veux savoir ce que le score maximum de match est donc l'instruction SQL suivante ferait l'affaire:

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 

En NHibernate, cela semble être un peu plus compliqué. Apparemment, HQL n'autorise pas les sous-requêtes dans la clause from, donc je ne peux pas vraiment l'utiliser. Je suis assez sûr que cela peut être fait avec ICriteria, mais je viens juste de commencer à utiliser NH, donc je n'arrive pas à le comprendre. J'ai essentiellement eu à ce qui suit:

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

Après que je l'ai joué avec divers assortiments de DetachedCriteria, mais semble juste aller en rond.

Répondre

6

Pour le monde HQL une seule requête le tour est joué ...

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>(); 

Hope this helps.

Mise à jour: Et pour le monde des critères, peut-être il ya une meilleure transformation des résultats, mais cela fonctionne juste :)

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"]; 
+0

Merci, le HQL fonctionne un régal. – Carl

1

je fait le faire de cette façon dans SQL:

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 

groupe est par toujours délicat dans les critères/HQL: parce qu'un groupe par clause ne peut retourner la colonne groupée et agrégats de toute autre colonne. Par conséquent, il est impossible de renvoyer une entité entière à partir d'une clause group by, uniquement l'ID que vous regroupez et agrège.

Pour cette raison, je fais habituellement par groupe à l'aide de requêtes SQL natif comme ceci:

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(); 
+0

Je n'ai même pas pensé à changer la requête comme ça, merci! Je suis en fait 'un de ceux' qui aurait déjà fait la plupart des choses en tant que procédures stockées, donc mettre SQL dans mon code n'aura probablement pas lieu. HQL m'a fait peur au début, mais je pense que c'est assez puissant, donc je vais suivre cette voie je pense. – Carl

+0

Ouais! Sauf que l'autre gars a pincé mon SQL et l'a fait dans HQL! – reach4thelasers

Questions connexes