代码之家  ›  专栏  ›  技术社区  ›  ireddick

休眠条件API-如何按集合大小排序?

  •  4
  • ireddick  · 技术社区  · 15 年前

    假设我有用户和用户组类。有一个可选的1多组到用户关联,并且关联是从两侧映射的(用户组侧通过一个名为“members”的属性,即散列集,用户侧通过属性“group”)。

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

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

    3 回复  |  直到 12 年前
        1
  •  1
  •   user164978    15 年前

    另一个选择是使用@formula注释,它基本上相当于创建一个嵌套的select,这样您就可以获得您的计数。

    在有问题的DB对象属性/成员(应该创建)上,向getter添加注释,如下所示:

    @公式(“(select count(table_name.id)from table where whatever…)” 公共长GetNewProperty{ 返还新财产; }

    然后直接以成员为目标获取您的计数值…

    注意:请注意,在公式批注中指定SQL时,当Hibernate处理当前对象表(this)时,必须直接指定字段名。因此,在WHERE子句中,当引用我怀疑是usergroup的当前对象表时,只需使用id或其本身的任何内容。

    为了使Hibernate工作并防止编译器抱怨,我必须为新属性设置一个setter。

    可能还有其他使用@formula的聪明方法,但我对这个还比较陌生,而且似乎没有太多关于这个主题的文档…

    如果您以前从未使用过嵌套的select,那么您可以先在SQL中重新创建它——这对我有帮助。

    希望这有帮助

        2
  •  3
  •   user1411778    12 年前

    默认情况下,不可能使用CiteriaAPI,但您可以扩展org.hibernate.criteria.order类。 本文将介绍如何扩展该类: http://blog.tremend.ro/2008/06/10/how-to-order-by-a-custom-sql-formulaexpression-when-using-hibernate-criteria-api

    我的解决办法是:

    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);
        }
    }
    

    Tosqlstring方法基于org.hibernate.criteria.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();
    

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

        3
  •  0
  •   skaffman    15 年前

    您可以这样做,方法是在实体上定义一个“派生属性”,它将是一个只读属性,返回实体内部集合的大小。定义派生属性的最简单方法是 documented here :

    更新,插入(可选-默认为 true):指定映射的 列应包含在SQL中 更新和/或插入语句。 将两者都设置为false允许 值为的“派生”属性 从其他属性初始化 映射到同一列,或 触发器或其它应用程序。

    一旦定义了属性,您就应该能够将属性名作为条件API中的ORDER子句使用,就像任何其他属性一样。不过,我自己也没试过。

    如果它可以工作,那么它很可能是作为内存排序完成的,因为它将无法将其映射到SQL。如果这是一个问题,那么上面的相同链接将说明如何使用自定义SQL片段实现派生属性:

    衍生出一个强大的特性 性质。这些属性是由 定义只读。财产 值在加载时计算。你 将计算声明为SQL 表达式。这就转化为 SQL中的select子句子查询 加载实例的查询: