Порядок в спящем режиме с нулями последний - PullRequest
31 голосов
/ 10 сентября 2010

Hibernate, используемый с PostgreSQL DB при упорядочении desc по столбцу, устанавливает нулевые значения выше, чем ненулевые.

Стандарт SQL99 предлагает ключевое слово «NULLS LAST», чтобы объявить, что нулевые значения должны быть меньше нуля.

Можно ли добиться поведения "NULLS LAST" с помощью API Критерии Hibernate?

Ответы [ 6 ]

43 голосов
/ 26 марта 2014

Эта функция была реализована в выпусках Hibernate 4.2.x и 4.3.x, как упоминалось ранее.

Может использоваться как, например:

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

Hibernate v4.3. Javadocs являются менее упущенными здесь .

15 голосов
/ 10 сентября 2010

Учитывая, что HHH-465 не исправлено и не будет исправлено в ближайшем будущем по причинам, указанным Стивом Эберсоле, лучшим вариантом будет использование CustomNullsFirstInterceptor, прикрепленногоили глобально, или специально, чтобы изменить оператор SQL.

Я выкладываю это ниже для читателей (кредиты Эмилио Дольче):

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

}
5 голосов
/ 18 июля 2017

Вы можете настроить «сначала пустые» / «последние пустые» в свойствах гибернации, так что по умолчанию он будет выбран любым критерием вызова: hibernate.order_by.default_null_ordering=last (или =first).

Подробнее см. этот гибернационный коммит .

2 голосов
/ 07 марта 2014

Другой вариант, если вы создаете SQL на лету и не используете Criteria API:

ЗАКАЗАТЬ КОАЛЕЦ (('0') [ASC | DESC]

Это работает как для varchar, так и для числовых столбцов.

2 голосов
/ 18 июля 2013

Вот мое обновление класса (Pascal Thivent):

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 имеет лимит / смещение после заказа на -Sathish 1 апреля '11 в 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, и это исправляетпроблема 'null выше, чем ненулевые', которая у нас была.

0 голосов
...