Hibernate Criteria API - how to order by collection size?

前端 未结 3 1102
走了就别回头了
走了就别回头了 2021-01-01 03:12

Assuming I have classes User and UserGroup. There is an optional 1-many group to user association and the association is mapped from both sides (the UserGroup side via a pro

3条回答
  •  刺人心
    刺人心 (楼主)
    2021-01-01 03:31

    It is not possible by default using Citeria API but you can extend org.hibernate.criterion.Order class. This article is about how to extend that class: http://blog.tremend.ro/2008/06/10/how-to-order-by-a-custom-sql-formulaexpression-when-using-hibernate-criteria-api

    My sollution is:

    public class SizeOrder extends Order {
    
        protected String propertyName;
        protected boolean ascending;
    
        protected SizeOrder(String propertyName, boolean ascending) {
            super(propertyName, ascending);
            this.propertyName = propertyName;
            this.ascending = ascending;
        }
    
        public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
            String role = criteriaQuery.getEntityName(criteria, propertyName) + '.' + criteriaQuery.getPropertyName(propertyName);
            QueryableCollection cp = (QueryableCollection) criteriaQuery.getFactory().getCollectionPersister(role);
    
            String[] fk = cp.getKeyColumnNames();
            String[] pk = ((Loadable) cp.getOwnerEntityPersister())
                    .getIdentifierColumnNames();
            return " (select count(*) from " + cp.getTableName() + " where "
                    + new ConditionFragment()
                            .setTableAlias(
                                    criteriaQuery.getSQLAlias(criteria, propertyName)
                            ).setCondition(pk, fk)
                        .toFragmentString() + ") "
                    + (ascending ? "asc" : "desc");
        }
    
        public static SizeOrder asc(String propertyName) {
            return new SizeOrder(propertyName, true);
        }
        public static SizeOrder desc(String propertyName) {
            return new SizeOrder(propertyName, false);
        }
    }
    

    The toSqlString method is based on org.hibernate.criterion.SizeExpression class. (Source: http://javasourcecode.org/html/open-source/hibernate/hibernate-3.6.0.Final/org/hibernate/criterion/SizeExpression.java.html)

    Example usage:

    hibernateSession.createCriteria(UserGroup.class).addOrder( SizeOrder.asc("members") ).list();
    

    this will list user groups ordered by the size of the members ascending, where "members" is the User collection in UserGroup entity.

提交回复
热议问题