Hibernate Criteria API - обходные пути предложения HAVING - PullRequest
10 голосов
/ 22 января 2009

Я написал запрос, используя Hibernate Criteria API, чтобы получить суммирование определенного значения, теперь мне нужно иметь возможность ограничить результат строками, в которых эта сумма больше или равна определенному значению.

Обычно для этого я использовал бы предложение HAVING в моем SQL, но API Criteria, похоже, не поддерживает это в данный момент.

В сыром SQL это то, что мне нужно сделать:

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

Один из обходных путей, о котором я подумал, - это использовать подзапрос в предложении FROM, который получает это значение суммирования, и использовать внешний запрос, чтобы ограничить его с помощью предложения WHERE.

Итак, в сыром SQL это будет выглядеть примерно так:

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

Может ли кто-нибудь указать мне правильное направление относительно того, как я мог бы написать это, используя Criteria API, или любые другие предложения / обходные пути, которые я могу использовать для решения проблемы HAVING?

Это код API Criteria, который у меня есть для приведенного выше примера

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

Спасибо!

Ответы [ 3 ]

8 голосов
/ 29 января 2009

Я не знаю, как Hibernate / NHibernate может использовать подзапрос в предложении FROM, но вы можете использовать их в предложении WHERE. Извиняюсь за любые ошибки кода Java / Hibernate, я больше знаком с 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));


Этот код должен приводить к SQL, похожему на:


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

Недостатком этого подхода является то, что он рассчитывает каждую из сумм дважды, это может отрицательно сказаться на производительности в зависимости от объема используемых данных - в этом случае вы захотите использовать запрос HQL, который поддерживает HAVING. пункт.

2 голосов
/ 04 февраля 2010

HHH-1700 был отмечен как дубликат HHH-1043 и поэтому не будет исправлен. Вы найдете мое решение и обходной путь, а также решения других людей на ЧЧЧ-1043 .

1 голос
/ 14 августа 2009
...