[英]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
并将maxResults
为20
。
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)
它将覆盖我的groupby
、 sum
和max
投影。
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.