简体   繁体   English

按查询分组的休眠条件行数

[英]Hibernate Criteria Row Count of Group By Query

I am trying to fetch the results of a group by query with a hibernate criteria.我正在尝试使用休眠条件通过查询获取组的结果。 As you can see in the code below, I am adding lots of projections into a ProjectionList.正如您在下面的代码中看到的,我在 ProjectionList 中添加了很多投影。 I have a pagination in front-end so if the client wants to fetch 20 results, I'm setting firstResult to 0 and maxResults to 20 .我在前端有一个分页,所以如果客户端想要获取 20 个结果,我将firstResult设置为0并将maxResults20

I need send total row count of this query, too.我也需要发送此查询的总行数。 However, if I use setProjection(Projections.rowCount) it will overwrite my groupby , sum , and max projections.但是,如果我使用setProjection(Projections.rowCount)它将覆盖我的groupbysummax投影。

How can I write something like select count(*) from ( myCriteria ) ?我怎样才能写出像select count(*) from ( myCriteria )

@Override
public SearchResult<ServiceIncomeSO> findServiceIncomesBySearch(IncomeQuery query, Pager pager) {
    Criteria criteria = createCriteria(ServiceIncome.class, "sin");
    criteria.createAlias("sin.partner", "ptr", JoinType.LEFT_OUTER_JOIN);

    if (StringUtils.isNotBlank(query.getPartnerKey())) {
        criteria.add(eq("ptr.key", query.getPartnerKey()));
    }

    if (StringUtils.isNotBlank(query.getPartnerTxt())) {
        criteria.add(disjunction() //
            .add(ilike("ptr.key", query.getPartnerTxt(), ANYWHERE)) //
            .add(ilike("ptr.name", query.getPartnerTxt(), ANYWHERE)) //
            .add(ilike("ptr.title", query.getPartnerTxt(), ANYWHERE))); //
    }

    if (CollectionUtils.isNotEmpty(query.getPartnerTypes())) {
        criteria.createAlias("ptr.partnerTypes", "partnerType", JoinType.LEFT_OUTER_JOIN);
        criteria.add(in("partnerType." + COLLECTION_ELEMENTS, query.getPartnerTypes()));
    }

    if (CollectionUtils.isNotEmpty(query.getCategories())) {
        criteria.createAlias("ptr.categories", "cat", JoinType.LEFT_OUTER_JOIN);
        criteria.add(in("cat.key", query.getCategories()));
    }

    if (query.getPeriodFromMonth() != null && query.getPeriodFromYear() != null) {
        addPeriodFrom(criteria, "sin.year", "sin.month", query.getPeriodFromYear(), query.getPeriodFromMonth());
    }

    if (query.getPeriodToMonth() != null && query.getPeriodToYear() != null) {
        addPeriodTo(criteria, "sin.year", "sin.month", query.getPeriodToYear(), query.getPeriodToMonth());
    }

    String[] fields;
    ProjectionList projection;
    if (query.getBreakout() == QueryBreakout.PARTNER) {
        projection = Projections.projectionList() //
            .add(Projections.groupProperty("sin.partner.key")) //
            .add(Projections.groupProperty("sin.year")) //
            .add(Projections.groupProperty("sin.month")) //
            .add(Projections.sum("sin.subscriberCount")) //
            .add(Projections.sum("sin.income"));//
        fields = new String[] { "partnerKey", "year", "month", "subscriberCount", "income" };
    } else {
        projection = Projections.projectionList() //
            .add(Projections.groupProperty("sin.partner.key")) //
            .add(Projections.groupProperty("sin.service.id")) //
            .add(Projections.groupProperty("sin.year")) //
            .add(Projections.groupProperty("sin.month")) //
            .add(Projections.max("sin.shortNumber")) //
            .add(Projections.sum("sin.subscriberCount")) //
            .add(Projections.sum("sin.income")) //
        ; //
        fields = new String[] { "partnerKey", "serviceId", "year", "month", "shortNumber", "subscriberCount", "income" };
    }

    criteria.setProjection(projection);
    criteria.addOrder(desc("sin.year")).addOrder(desc("sin.month"));

    criteria.setFirstResult(pager.getOffset());
    criteria.setMaxResults(pager.getMax());

    List<ServiceIncomeSO> list = ((List<Object[]>) criteria.list()).stream() //
        .map(values -> JavaLangUtils.setProperties(new ServiceIncomeSO(), fields, values)) //
        .collect(Collectors.toList()); //

    // TODO How to get count without retrieving all the data?
    int totalResults = 0;

    return new SearchResult<>(list, totalResults, pager.getMax(), pager.getOffset());
}

private void addPeriodFrom(Criteria criteria, String yearColumn, String periodColumn, int yearFrom, int periodFrom) {
    criteria.add(disjunction() // OR
        .add(and(eq(yearColumn, yearFrom), ge(periodColumn, periodFrom))) // year == yearFrom && period >= periodFrom
        .add(gt(yearColumn, yearFrom))); // year > yearFrom
}

private void addPeriodTo(Criteria criteria, String yearColumn, String periodColumn, int yearFrom, int periodFrom) {
    criteria.add(disjunction() // OR
        .add(and(eq(yearColumn, yearFrom), le(periodColumn, periodFrom))) // year == yearFrom && period <= periodFrom
        .add(lt(yearColumn, yearFrom))); // year < yearFrom
}

I can write the same query in plain SQL but cannot do it in Hibernate Criteria API.我可以用普通 SQL 编写相同的查询,但不能在 Hibernate Criteria API 中执行。

Select Query:选择查询:

SELECT 
    PARTNER_KEY, 
    SERVICE_ID, 
    INCOME_YEAR, 
    INCOME_MONTH, 
    SUM(SUBSCRIBER_COUNT), 
    SUM(INCOME) 
FROM 
    PP_SERVICE_INCOME 
WHERE 
    PARTNER_KEY = 'PART32143' 
GROUP BY 
    PARTNER_KEY, 
    SERVICE_ID, 
    INCOME_YEAR, 
    INCOME_MONTH;

Select Result:选择结果:

PARTNER_KEY SERVICE_ID INCOME_YEAR INCOME_MONTH SUM(SUBSCRIBER_COUNT) SUM(INCOME) 
----------- ---------- ----------- ------------ --------------------- ----------- 
PART32143   1          2016        1            1234                  175000      
PART32143   1          2017        1            1234                  175390      
PART32143   1          2016        6            1234                  151100      
PART32143   1          2017        0            1234                  157800      
PART32143   1          2016        7            1234                  175220      
PART32143   1          2016        2            1234                  143000      
PART32143   1          2016        0            1234                  150000      
PART32143   1          2017        2            1234                  143012      
PART32143   1          2016        8            1234                  143330      

Count Query:计数查询:

SELECT 
    COUNT(*) 
FROM (
    SELECT 
        PARTNER_KEY, 
        SERVICE_ID, 
        INCOME_YEAR, 
        INCOME_MONTH, 
        SUM(SUBSCRIBER_COUNT), 
        SUM(INCOME) 
    FROM 
        PP_SERVICE_INCOME 
    WHERE 
        PARTNER_KEY = 'PART32143' 
    GROUP BY 
        PARTNER_KEY, 
        SERVICE_ID, 
        INCOME_YEAR, 
        INCOME_MONTH
    );

Count Result: 9计数结果:9

For this, first you do group by using DetachedCriteria like this,为此,首先您像这样使用DetachedCriteria进行group by

DetachedCriteria dcrit = DetachedCriteria.forClass(Student.class);
dcrit.setProjection(Projections.projectionList()
            .add(Projections.groupProperty("studentname").as("name")));

After grouping get the row count using criteria by adding the DetachedCriteria as a subquery for the Criteria like the following,分组后,通过添加DetachedCriteria作为Criteria的子查询,使用条件获取行数,如下所示,

Criteria crit = sessionFactory.getCurrentSession().createCriteria(Student.class);
crit.add(Subqueries.propertyIn("id", dcrit));
crit.setProjection( Projections.rowCount() );
return ((Number) crit.uniqueResult()).intValue();

What you first want to do is instead of creating a Criteria for your ServiceIncome inner query, you want to create it as a DetachedCriteria as follows:您首先要做的不是为ServiceIncome内部查询创建Criteria ,而是希望将其创建为DetachedCriteria ,如下所示:

DetachedCriteria myCriteria = DetachedCriteria.forClass( 
  ServiceIncome.class, 
  "sin"
);

Then you want to create your outer criteria like you normally would using the Session and then specify the subquery as the DetachedCriteria we specified above with the desired projection.然后,您想像通常使用Session一样创建外部条件,然后将子查询指定为我们在上面指定的DetachedCriteria和所需的投影。

Criteria outerCriteria = session.createCriteria( ServiceIncome.class, "osin" );
outerCriteria.add( Subqueries.propertyIn( "id", myCriteria ) );
outerCriteria.setProjection( Projections.rowCount );

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM