Hibernate ordene con nulos por última vez

Hibernate utilizado con PostgreSQL DB mientras ordena desc por una columna pone valores nulos más altos que nulos.

El estándar SQL99 ofrece la palabra clave “NULLS LAST” para declarar que los valores nulos deben ser inferiores a los valores nulos.

¿Se puede lograr el comportamiento “NULLS LAST” utilizando la API de criterios de Hibernate?

Dado que HHH-465 no es fijo y no va a repararse en un futuro cercano por las razones dadas por Steve Ebersole, su mejor opción sería usar el CustomNullsFirstInterceptor adjunto al problema ya sea global o específicamente para alterar la statement de SQL.

Lo publico a continuación para los lectores (créditos a 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 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); } } 

Esta característica se implementó durante las versiones de Hibernate 4.2.x y 4.3.x como se mencionó anteriormente.

Se puede usar como por ejemplo:

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

Los javadocs de Hibernate v4.3 son menos omisos aquí .

Puede configurar “null primero” / “nulls last” en propiedades de hibernación, por lo que será seleccionado por cualquier criterio de llamada por defecto: hibernate.order_by.default_null_ordering=last (or =first ).

Vea este compromiso de hibernación para más detalles.

Aquí está mi actualización de la clase por (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"); } } } 

Esto soluciona el problema:

Esto se rompe si sql tiene límite / desplazamiento después de la orden por – Sathish Abr 1 ’11 a las 14:52

También he aquí cómo puedes usar esto dentro de JPA (hibernación):

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

He probado esto en postgres y soluciona el problema de ‘nulls are higher than non-nulls’ que estábamos teniendo.

Otra variante, si creas SQL sobre la marcha y no usas Criteria API:

ORDEN DE COALESCE (‘0’) [ASC | DESC]

Esto funciona bien para varchar o columnas numéricas.

Parece que hay una solicitud de cambio / ticket de error abierto para este