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

休眠排序依据,最后为空值

  •  30
  • mgamer  · 技术社区  · 14 年前

    Hibernate与PostgreSQL DB一起使用,同时按列排序DESC时,将空值设置为高于非空值。

    sql99 standard提供关键字“nulls last”来声明应将空值放在小于不为空的位置。

    是否可以使用Hibernate的标准API实现“nulls last”行为?

    6 回复  |  直到 7 年前
        1
  •  15
  •   Chris Betti    10 年前

    鉴于 HHH-465 由于Steve Ebersole给出的原因,您最好的选择是使用 CustomNullsFirstInterceptor 附加到该问题的全局或专门用于更改SQL语句。

    我在下面为读者发布(归功于Emilio Dolce):

    public class CustomNullsFirstInterceptor extends EmptyInterceptor {
    
        private static final long serialVersionUID = -3156853534261313031L;
    
        private static final String ORDER_BY_TOKEN = "order by";
    
        public String onPrepareStatement(String sql) {
    
            int orderByStart = sql.toLowerCase().indexOf(ORDER_BY_TOKEN);
            if (orderByStart == -1) {
                return super.onPrepareStatement(sql);
            }
            orderByStart += ORDER_BY_TOKEN.length() + 1;
            int orderByEnd = sql.indexOf(")", orderByStart);
            if (orderByEnd == -1) {
                orderByEnd = sql.indexOf(" UNION ", orderByStart);
                if (orderByEnd == -1) {
                    orderByEnd = sql.length();
                }
            }
            String orderByContent = sql.substring(orderByStart, orderByEnd);
            String[] orderByNames = orderByContent.split("\\,");
            for (int i=0; i<orderByNames.length; i++) {
                if (orderByNames[i].trim().length() > 0) {
                    if (orderByNames[i].trim().toLowerCase().endsWith("desc")) {
                        orderByNames[i] += " NULLS LAST";
                    } else {
                        orderByNames[i] += " NULLS FIRST";
                    }
                }
            }
            orderByContent = StringUtils.join(orderByNames, ",");
            sql = sql.substring(0, orderByStart) + orderByContent + sql.substring(orderByEnd); 
            return super.onPrepareStatement(sql);
        }
    
    }
    
        2
  •  41
  •   José Andias    10 年前

    如前所述,此功能已在Hibernate 4.2.x和4.3.x版本中实现。

    例如:

    Criteria criteria = ...;
    criteria.addOrder( Order.desc( "name" ).nulls(NullPrecedence.FIRST) );
    

    Hibernate v4.3 JavaDocs的灵活性较低 here .

        3
  •  5
  •   uwolfer    7 年前

    您可以在Hibernate属性中配置“Nulls First”/“Nulls Last”,以便默认情况下任何条件调用都会拾取它: hibernate.order_by.default_null_ordering=last (或) =first )

    this hibernate commit 详情。

        4
  •  2
  •   jstricker    11 年前

    以下是我对班级的最新更新(帕斯卡·蒂凡特):

    for (int i = 0; i < orderByNames.length; i++) {
        if (orderByNames[i].trim().length() > 0) {
            String orderName = orderByNames[i].trim().toLowerCase();
            if (orderName.contains("desc")) {
                orderByNames[i] = orderName.replace("desc", "desc NULLS LAST");
            } else {
                orderByNames[i] = orderName.replace("asc", "asc NULLS FIRST");
            }
        }
    }
    

    这解决了问题:

    如果SQL在11年4月1日星期六14:52的订单后有限制/偏移,则此操作将中断。

    下面还介绍了如何在JPA(Hibernate)中使用它:

    Session session = entityManager.unwrap(Session.class);
    Session nullsSortingProperlySession = null;
    try {
        // perform a query guaranteeing that nulls will sort last
        nullsSortingProperlySession = session.getSessionFactory().withOptions()
            .interceptor(new GuaranteeNullsFirstInterceptor())
            .openSession();
    } finally {
        // release the session, or the db connections will spiral
        try {
            if (nullsSortingProperlySession != null) {
                nullsSortingProperlySession.close();
            }
        } catch (Exception e) {
            logger.error("Error closing session", e);
        }
    }
    

    我在Postgres上测试过,它修复了“空值高于非空值”的问题。

        5
  •  2
  •   Gennady Nikolaev    10 年前

    另一个变种,如果您动态创建SQL并且不使用标准API:

    按合并(,'0')[asc desc]排序

    这适用于varchar或numeric列。