How to order result of hibernate based on a specific order

自古美人都是妖i 提交于 2019-12-01 15:39:29

With JPQL (HQL):

select fname from Name
where upper(fname) like :fnameStart or upper(fname) like :fnameMiddle
order by (case when upper(fname) like :fnameStart then 1 else 2 end), fname

query.setParameter("fnameStart", "XX%");
query.setParameter("fnameMiddle", "% XX%");

With Criteria

With Criteria it's much trickier. Firstly, you have to resort to native SQL in the order clause. Secondly, you have to bind the variable.

public class FirstNameOrder extends Order {
    public FirstNameOrder() {
        super("", true);
    }

    @Override
    public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
        return "case when upper(FIRST_NAME) like ? then 1 else 2 end";
    }
}

The case expression syntax and the upper function name should be changed in accordance with your database (and the column name if it's different, of course).

It is easy to add this to the Criteria, but there is no API to bind the parameter.

I tried to trick Hibernate by passing in an unused variable to the custom sql restriction so that it is effectively used for the variable in the order by clause:

Criteria criteria = session.createCriteria(Name.class, "name")
   .add(Restrictions.disjunction()
      .add(Restrictions.ilike("name.fname", fname + "%"))
      .add(Restrictions.ilike("name.fname", "%" + " " + fname + "%")))
   .setProjection(Projections.property("name.fname").as("fname"))
   .add(Restrictions.sqlRestriction("1 = 1", fname + "%", StringType.INSTANCE))
   .addOrder(new FirstNameOrder())
   .addOrder(Order.asc("fname"));

and it works fine.

Obviously, this solution is not recommended and I suggest using JPQL for this query.

Hibernate supports Order: http://docs.jboss.org/hibernate/orm/4.2/devguide/en-US/html/ch11.html#ql-ordering Because of the special criteria, I think you have to custom the Order in Hibernate. This link may help: http://blog.tremend.ro/2008/06/10/how-to-order-by-a-custom-sql-formulaexpression-when-using-hibernate-criteria-api/

Run two selects, one filtered for all the strings starting with 'XX', the second filtered for the others.

You can use Predicates in criteria... something like this:

public List<Name> findByParameter(String key, String value, String orderKey)

            CriteriaBuilder builder = this.entityManager.getCriteriaBuilder();
            CriteriaQuery<Name> criteria = builder.createQuery(this.getClazz());
            Root<Name> root = criteria.from(Name.getClass());
            criteria.select(root);
            List<Predicate> predicates = new ArrayList<Predicate>();
            predicates.add(builder.equal(root.get(key), value));
            criteria.where(predicates.toArray(new Predicate[predicates.size()]));
            if (orderKey!=null  && !orderKey.isEmpty()) {
                criteria.orderBy(builder.asc(root.get(orderKey)));
            }
            result = this.entityManager.createQuery(criteria).getResultList();

        return result;
}

Stupid but it may work for your case.

Since you got your correct result you can just reconstruct your results as follows:

  1. pick up all results starting with XX you put them into a list L1 and do the normal sort like Collections.sort(L1);
  2. for all other results, do the same like Collections.sort(L2)as list of L2
  3. At last , put them together

    List newList = new ArrayList(L1);

    newList.addAll(L2);

Please note. Collections.sort are following the natural ordering of its elements.

If you don't want to sort the result in memory,you can modify your criteria,I'll show you the SQL

select * from table where fname like 'XX%' order by fname
union all
select * from table where fname like '% XX%' order by fname
union all
select * from table where fname like '% XX' order by fname

the result will be your order and alphabetical and then apply your filter.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!