0

i am trying to fetch only max(assetHistoryId) but my below code returing 3 columns max(assetHistoryId), eventId, and assetIdentifier in result. how to group the columns with out projection using criteria. you can find my code below.

final Criteria agcriteria  = createCriteria(someclass.class);    
    agcriteria.add(Restrictions.in("eventId", listOfEventIds));
    agcriteria.add(Restrictions.ne("action", "T"));
    agcriteria.add(
            Restrictions.between("modifyDate", lastProcessedTime,
                    batchStartTime));
    agcriteria.setProjection(Projections.projectionList()
            .add(Projections.groupProperty("assetIdentifier"))
            .add(Projections.groupProperty("eventId"))
            .add(Projections.max("assetHistoryId")));
    val = agcriteria.list(); 

please help me any one ?

Ranjit
  • 1
  • 3
  • if you are trying to fetch "only max(xxx)", your query shouldn't had been returned an unique result? – G Bisconcini Feb 06 '15 at 14:08
  • same functionality with sql code returning list of assetHistoryIds but with hibernate criteria it is projecting grouping columns also. i don't want grouping columns in my result i want only max( assetHistoryId). like select max(assethistoryid) from table. but with hibernate i am getting select max(assethistoryid),assetidentifer,eventnumber from table. hope you understand – Ranjit Feb 06 '15 at 17:23
  • Please any one help me to my issue? – Ranjit Feb 08 '15 at 07:20
  • @Ranjit, were you able to solve this? – Rishab178 Jul 22 '19 at 10:14

2 Answers2

0

If i understand you correctly, you want only max(assetHistoryId) without any other column details. You can try something like this:

Criteria agcriteria  = createCriteria(someclass.class);
agcriteria.setProjection(Projections.projectionList()
.add(Projections.max("assetHistoryId")));

You can add restrictions to it, if any... like this: agcriteria.add(Criteria c); or the same set of conditions

agcriteria.add(Restrictions.in("eventId", listOfEventIds));
agcriteria.add(Restrictions.ne("action", "T"));
agcriteria.add(
            Restrictions.between("modifyDate", lastProcessedTime,
                    batchStartTime));
subbu
  • 524
  • 6
  • 16
0

Ok, boys and girls. I know it's a necro and Hibernate Criteria Api was deprecated long ago. But still there are systems which use this API, so hope it will be useful.

I could not find a way to do it with built-in hibernate projections, so I've decided to make my own ones. First of all we will need to create a new projection class which will produce nothing in SELECT clause, but still have it in group clause.

public class NoPropertyGroupProjection extends SimpleProjection {

    private String propertyName;

    protected NoPropertyGroupProjection(String propertyName) {

        this.propertyName = propertyName;

    }

    @Override
    public boolean isGrouped() {
        return true;
    }

    @Override
    public Type[] getTypes(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
        return new Type[] { };
    }

    @Override
    public String toSqlString(Criteria criteria, int position, CriteriaQuery criteriaQuery) throws HibernateException {

        return "";

    }

    @Override
    public String toGroupSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {

        return StringHelper.join( ", ", criteriaQuery.getColumns( propertyName, criteria ) );

    }

    @Override
    public String toString() {
        return propertyName;
    }

}

That's a copy of PropertyProjection from the version of Hibernate I have with some changes.

It won't work alone (it is just much complicated to force it work alone), but in most cases we still need something to be selected.

So the next thing we need is to fix ProjectionList as it will break with empty column we're trying to pass it. So, here's the next class. Shame elements list is private, but we have sufficient getters to achieve our goal.

public class ProjectionListWithOnlyGroupBySupport extends ProjectionList {

    @Override
    public String toSqlString(Criteria criteria, int loc, CriteriaQuery criteriaQuery) throws HibernateException {
        final StringBuilder buf = new StringBuilder();
        String separator = "";

        for ( int i = 0; i < this.getLength(); i++ ) {

            Projection projection = this.getProjection(i);

            String addition = projection.toSqlString( criteria, loc, criteriaQuery );

            if (!"".equals(addition)) {

                buf.append(separator).append(addition);
                loc += getColumnAliases(loc, criteria, criteriaQuery, projection).length;
                separator = ", ";

            }

        }
        return buf.toString();
    }

    private static String[] getColumnAliases(int loc, Criteria criteria, CriteriaQuery criteriaQuery, Projection projection) {
        return projection instanceof EnhancedProjection
                ? ( (EnhancedProjection) projection ).getColumnAliases( loc, criteria, criteriaQuery )
                : projection.getColumnAliases( loc );
    }
}

Again, small adjustments for the original class. Now we have everything needed to accomplish our goal. But for convenience we will create one more class.

public final class AdvancedProjections {

    public static NoPropertyGroupProjection groupBy(String propertyName) {
        return new NoPropertyGroupProjection( propertyName );
    }

    public static ProjectionList projectionList() {
        return new ProjectionListWithOnlyGroupBySupport();
    }

}

After we've created all these classes, we can change the code from the question:

final Criteria agcriteria  = createCriteria(someclass.class);    
    agcriteria.add(Restrictions.in("eventId", listOfEventIds));
    agcriteria.add(Restrictions.ne("action", "T"));
    agcriteria.add(
            Restrictions.between("modifyDate", lastProcessedTime,
                batchStartTime));
    agcriteria.setProjection(AdvancedProjections.projectionList()
            .add(Projections.max("assetHistoryId"))
            .add(AdvancedProjections.groupBy("assetIdentifier"))
            .add(AdvancedProjections.groupBy("eventId")));
    val = agcriteria.list();

Voila!

Rigeborod
  • 356
  • 2
  • 6