how can get count of rows in hibernate when hql have group by?

ali akbar azizkhani picture ali akbar azizkhani · Sep 13, 2016 · Viewed 10.5k times · Source

I have hql query that have group by .In pagination result i want to get count of all result to show in pagination . In query that donot have group by .I write a utility that create count of query from hql query like this

select u 
from Personel u 
where u.lastname='azizkhani'

i find main "from" keyword and substring hql and add count(*) and then make this query

select count(*) 
from Personel u  
where u.lastname='azizkhani'

when i have query that contain group by i can not do it like this

select u.lastname,count(*) 
from Personel u 
group by u.lastname;

count of that query in sql is

select count(*) 
   from (
         select u.lastname,count(*) 
         from tbl_personel u 
         group  by u.lastname
    )

how can i generate group by query from hql ??

I have GenericRepository that have method like this

public <U> PagingResult<U> getAllGrid(String hql,Map<String, Object> params,PagingRequest searchOption);

and developer call that like this

   String hqlQuery = " select e from Personel e where 1<>2 and e.lastname=:lastname";

    HashMap<String, Object> params = new HashMap<String, Object>();
    params.put("lastname", 'azizkhani');


    return getAllGrid(hqlQuery, params, new PagingRequest( 0/*page*/, 10 /*size*/) );

in GenericRepository i will return PagingResult object that have property

public class PagingResult<T> {

    private int totalElements;

    @JsonProperty("rows")
    private List<T> items;

    public PagingResult() {

    }

    public PagingResult(int totalElements, List<T> items) {
        super();
        this.totalElements = totalElements;
        this.items = items;
    }


    public int getTotalElements() {
        return totalElements;
    }

    public void setTotalElements(int totalElements) {
        this.totalElements = totalElements;
    }


    public List<T> getItems() {
        return items;
    }

    public void setItems(List<T> items) {
        this.items = items;
    }

}

In GenericRepository i will execute two query ,first one for get 10 result and second for get totalRecords .Developer just send Hql .I will make hql for get totalcount . for query that dose not have "distinct" or "group by" i make hql .but when hql have "distinct" and "group by" i have problem .

public <U> PagingResult<U> getAllGrid(String hql, Map<String, Object> params, PagingRequest searchOption) {
        Session session = getSession();
        applyDafaultAuthorizeFilter(session);


        Query query = session.createQuery(hql);
        if (searchOption != null) {
            if (searchOption.getSize() > 0) {
                query.setFirstResult(searchOption.getPage() * searchOption.getSize());
                query.setMaxResults(searchOption.getSize());
            }
        }
        if (params != null)
            HQLUtility.setQueryParameters(query, params);

        List<U> list = query.getResultList();

        Query countQuery = session.createQuery("select count(*) " + HQLUtility.retriveCountQueryFromHql(hql));

        if (params != null)
            HQLUtility.setQueryParameters(countQuery, params);

        int count = ((Long) countQuery.uniqueResult()).intValue();
        if (searchOption != null)
            return new PagingResult<U>(searchOption.getPage(), count, searchOption.getSize(), list);
        else
            return new PagingResult<U>(0, count, 0, list);
    }


   public static StringBuffer retriveCountQueryFromHql(StringBuffer jql) {
        if(jql.indexOf("order by")>=0)
            jql.replace(jql.indexOf("order by"), jql.length(),"");
        String mainQuery = jql.toString();

        jql = new StringBuffer(jql.toString().replace('\t', ' '));
        int firstIndexPBas = jql.indexOf(")");
        int firstIndexPBaz = jql.lastIndexOf("(", firstIndexPBas);
        while (firstIndexPBas > 0) {
            for (int i = firstIndexPBaz; i < firstIndexPBas + 1; i++)
                jql.replace(i, i + 1, "*");
            firstIndexPBas = jql.indexOf(")");
            firstIndexPBaz = jql.lastIndexOf("(", firstIndexPBas);
        }
        int Indexfrom = jql.indexOf(" from ");
        return new StringBuffer(" " + mainQuery.substring(Indexfrom, jql.length()));
    }

    public void applyDafaultAuthorizeFilter(Session session) {
        Filter filter = session.enableFilter("defaultFilter");
        filter.setParameter("userId", SecurityUtility.getAuthenticatedUserId());
        filter.setParameter("orgId", SecurityUtility.getAuthenticatedUserOrganization().getId());
    }

how can i solve this problem without change signature of my GenericRepository???

I think i have solution that convert hql to sql and create native query like this select count(*) from ( hql_to_sql) but i have two problem

  1. hql to sql dose not have api that support parameter
  2. hql to sql dose not have api that support hibernate filter

Answer

Christian Beikov picture Christian Beikov · Mar 23, 2017

Why not replace the group by with a count(distinct)?

So instead of

select u from tbl_personel u group by u.lastname

you do

select count(distinct u.lastname) from tbl_personel u