Hibernate Criteria API - 如何按集合大小排序?

ire*_*ick 5 hibernate criteria-api

假设我有类 User 和 UserGroup。有一个可选的 1-many 组到用户关联,并且关联是从双方映射的(UserGroup 端通过名为“members”的属性,它是一个 HashSet,User 端通过属性“group”)。

使用 Criteria API,如何查询按组成员计数排序的所有组?

(编辑)当我问这个问题时,我应该指出分页正在 SQL 中执行,所以如果可能的话,排序也应该在 SQL 中执行。

小智 5

默认情况下无法使用 Citeria API,但您可以扩展 org.hibernate.criterion.Order 类。这篇文章是关于如何扩展该类:http : //blog.tremend.ro/2008/06/10/how-to-order-by-a-custom-sql-formulaexpression-when-using-hibernate-criteria-接口

我的解决方案是:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

toSqlString 方法基于 org.hibernate.criterion.SizeExpression 类。(来源:http : //javasourcecode.org/html/open-source/hibernate/hibernate-3.6.0.Final/org/hibernate/criterion/SizeExpression.java.html

用法示例:

hibernateSession.createCriteria(UserGroup.class).addOrder( SizeOrder.asc("members") ).list();
Run Code Online (Sandbox Code Playgroud)

这将列出按成员大小升序排列的用户组,其中“成员”是 UserGroup 实体中的用户集合。


小智 2

另一种选择是使用 @Formula 注释,它基本上相当于创建一个嵌套选择,以便您可以进行计数。

在有问题的数据库对象属性/成员(您应该创建)上,将注释添加到 getter,如下所示:

@Formula("(SELECT COUNT(TABLE_NAME.ID) FROM TABLE WHERE 不管...)") public long getNewProperty{ return newProperty; }

然后直接定位该成员以获取您的计数值...

注意:请注意,在公式注释中指定 sql 时,在引用当前对象表(this)时必须直接指定字段名称,因为 hibernate 会自行处理此问题。因此,在 WHERE 子句中,在引用当前对象表(我怀疑是 UserGroup)时,只需使用 ID 或其他任何内容。

我必须为我的新属性设置一个设置器,以便休眠功能正常工作并防止编译器抱怨。

可能还有其他聪明的方法来使用 @Formula,但我对此很陌生,并且似乎没有关于该主题的太多文档......

如果您以前从未使用过嵌套 SELECTS,那么您可能首先在 sql 中重新创建 - 这对我有帮助。

希望这可以帮助