tamaño - ordenar cadenas en java
Cómo ordenar el resultado de hibernación basado en un orden específico (6)
Necesito enviar una consulta para recuperar valores que tengan un grupo específico de caracteres de la siguiente manera:
Digamos que estoy interesado en ''XX'', por lo que debería buscar cualquier campo cuyo valor comience con ''XX'' o tenga ''XX'' (espacio XX). Por ejemplo, XXCDEF
, PD XXRF
y CMKJIEK XX
son resultados válidos.
Tengo la siguiente consulta que devuelve los resultados correctos, pero debo clasificarlos de manera que primero devuelva aquellos con XX
al principio y luego otros resultados. De la siguiente manera
XXABCD
XXPLER
XXRFKF
AB XXAB
CD XXCD
ZZ XXOI
POLO XX
Código
Criteria criteria = session.createCriteria(Name.class, "name")
.add(Restrictions.disjunction()
.add(Restrictions.ilike("name.fname", fname + "%"))
.add(Restrictions.ilike("name.fname", "%" + " " + fname + "%"))
)
.setProjection(Projections.property("name.fname").as("fname"));
List<String> names = (List<String>) criteria.list();
Ejecute dos selecciones, una filtrada para todas las cadenas que comienzan con ''XX'', la segunda filtrada para las demás.
Estúpido pero puede funcionar para tu caso.
Como obtuvo el resultado correcto, puede reconstruir los resultados de la siguiente manera:
- seleccione todos los resultados que comiencen con XX, póngalos en una lista L1 y realice el ordenamiento normal como Collections.sort (L1);
- para todos los demás resultados, haga lo mismo como Collections.sort (L2) como lista de L2
Por fin, juntarlos
List newList = new ArrayList (L1);
newList.addAll (L2);
Tenga en cuenta. Las colecciones.sort están siguiendo el orden natural de sus elementos.
Hibernate admite Orden: http://docs.jboss.org/hibernate/orm/4.2/devguide/en-US/html/ch11.html#ql-ordering Debido a los criterios especiales, creo que tiene que personalizar la Orden en Hibernar. Este enlace puede ayudar: http://blog.tremend.ro/2008/06/10/how-to-order-by-a-custom-sql-formulaexpression-when-using-hibernate-criteria-api/
Puedes usar Predicados en criterios ... algo como esto:
public List<Name> findByParameter(String key, String value, String orderKey)
CriteriaBuilder builder = this.entityManager.getCriteriaBuilder();
CriteriaQuery<Name> criteria = builder.createQuery(this.getClazz());
Root<Name> root = criteria.from(Name.getClass());
criteria.select(root);
List<Predicate> predicates = new ArrayList<Predicate>();
predicates.add(builder.equal(root.get(key), value));
criteria.where(predicates.toArray(new Predicate[predicates.size()]));
if (orderKey!=null && !orderKey.isEmpty()) {
criteria.orderBy(builder.asc(root.get(orderKey)));
}
result = this.entityManager.createQuery(criteria).getResultList();
return result;
}
Si no desea ordenar el resultado en la memoria, puede modificar sus criterios, le mostraré el SQL
select * from table where fname like ''XX%'' order by fname
union all
select * from table where fname like ''% XX%'' order by fname
union all
select * from table where fname like ''% XX'' order by fname
El resultado será su orden y alfabético y luego aplicará su filtro.
Con JPQL (HQL) :
select fname from Name
where upper(fname) like :fnameStart or upper(fname) like :fnameMiddle
order by (case when upper(fname) like :fnameStart then 1 else 2 end), fname
query.setParameter("fnameStart", "XX%");
query.setParameter("fnameMiddle", "% XX%");
Con criterios
Con Criteria
es mucho más complicado. En primer lugar, debe recurrir a SQL nativo en la cláusula de order
. En segundo lugar, hay que enlazar la variable.
public class FirstNameOrder extends Order {
public FirstNameOrder() {
super("", true);
}
@Override
public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
return "case when upper(FIRST_NAME) like ? then 1 else 2 end";
}
}
La sintaxis de la expresión del caso y el nombre de la función upper
deben cambiarse de acuerdo con su base de datos (y el nombre de la columna si es diferente, por supuesto).
Es fácil agregar esto a los Criteria
, pero no hay API para enlazar el parámetro.
Intenté engañar a Hibernate pasando una variable no utilizada a la restricción sql personalizada para que se use efectivamente para la variable en la cláusula order by
:
Criteria criteria = session.createCriteria(Name.class, "name")
.add(Restrictions.disjunction()
.add(Restrictions.ilike("name.fname", fname + "%"))
.add(Restrictions.ilike("name.fname", "%" + " " + fname + "%")))
.setProjection(Projections.property("name.fname").as("fname"))
.add(Restrictions.sqlRestriction("1 = 1", fname + "%", StringType.INSTANCE))
.addOrder(new FirstNameOrder())
.addOrder(Order.asc("fname"));
y funciona bien.
Obviamente, esta solución no se recomienda y sugiero usar JPQL para esta consulta.