2009-01-21 10 views
10

J'ai écrit une requête en utilisant Hibernate Criteria API pour récupérer une somme d'une valeur particulière, maintenant je dois être en mesure de restreindre le résultat aux lignes où cette somme est supérieure ou égale à une valeur particulière.Hibernate Criteria API - HAVING clause work contourne

Normalement, j'utiliserais une clause HAVING dans mon SQL pour ce faire, mais l'API Criteria ne semble pas supporter cela pour le moment.

Dans SQL cru ce que je besoin de le faire:

SELECT user_pk, sum(amount) as amountSum 
FROM transaction 
GROUP BY user_pk 
HAVING amountSum >=50; 

Un travail autour que je pensais est d'utiliser un sous-requête dans la clause FROM qui saisit cette valeur de sommation et utiliser une requête externe pour le restreindre en utilisant une clause WHERE.

Ainsi, dans SQL brut, il ressemblera à quelque chose comme:

SELECT user_pk, amountSum 
FROM (SELECT user_pk, sum(amount) as amountSum 
     FROM transaction 
     GROUP BY user_pk) 
WHERE amountSum > 50; 

Quelqu'un peut-il me diriger dans la bonne direction à la façon dont je pourrais écrire cela en utilisant l'API de critères ou d'autres suggestions/contournements I peut utiliser pour résoudre le problème HAVING?

Ceci est le code de l'API critères que j'ai pour l'exemple ci-dessus

DetachedCriteria criteria = DetachedCriteria.forClass(Transaction.class,"transaction"); 
criteria.setProjection(criteria.setProjection(Projections.projectionList().add(
     Projections.groupProperty("user.userPK").as("user_pk")).add(
      Projections.sum("transaction.amount").as("amountSum"))); 

Merci à!

Répondre

8

Je ne connais pas de méthode permettant à Hibernate/NHibernate d'utiliser une sous-requête dans la clause FROM, mais vous pouvez les utiliser dans la clause WHERE. Toutes mes excuses pour toute erreur de code Java/Hibernate, je suis plus familier avec C#/NHibernate.

 

DetachedCriteria subQuery = DetachedCriteria.forClass(Transaction.class); 
subQuery.setProjection(Projections.sum("amount")); 
subQuery.add(Expression.eqProperty("userPk", "tOuter.userPk")); 

DetachedCriteria outerQuery = DetachedCriteria.forClass(Transaction.class, "tOuter"); 
outerQuery.setProjection(Projections.projectionList() 
    .Add(Projections.sum("amount").as("sumAmount")) 
    .Add(Projections.groupProperty("userPk").as("user_pk")); 
outerQuery.add(Subqueries.le(50, subQuery)); 

 

Ce code devrait se traduire par SQL similaire à:

 

SELECT tOuter.userPk as user_pk, sum(tOuter.amount) as sumAmount 
FROM transaction tOuter 
WHERE 50 <= (SELECT sum(amount) FROM transaction WHERE userPk = tOuter.userPk) 
GROUP BY tOuter.userPk 
 

L'inconvénient de cette approche est qu'elle calcule chacune des sommes deux fois, cela pourrait avoir un effet néfaste sur la performance en fonction du montant des données impliquées - auquel cas vous voudrez utiliser une requête HQL qui supporte la clause HAVING.

2

HHH-1700 a été marqué comme un double de HHH-1043, et ne sera donc pas fixé. Vous trouverez ma solution et solution de contournement, ainsi que d'autres personnes, sur HHH-1043.

+0

c'était il y a 7 ans et toujours pas patché dans hibernate, j'ai besoin d'appliquer le correctif pour la version 4.3.6 ou plus récent mais le code a été changé tellement que je ne sais pas comment le faire. Quelqu'un a ce patch mis à jour? –

Questions connexes