web-dev-qa-db-fra.com

Ordre de requête nommé Hibernate par paramètre

Salut quelqu'un peut-il m'indiquer comment nous pouvons passer une clause order by en tant que paramètre nommé à hql

Ex:

Travaux:

select tb from TransportBooking as tb

and TIMESTAMP(tb.bookingDate, tb.bookingTime) >= current_timestamp() order by tb.bookingDate

Ne marche pas:

select tb from TransportBooking as tb

and TIMESTAMP(tb.bookingDate, tb.bookingTime) >= current_timestamp() order by :order
17
Jet Abe

Non pris en charge, les paramètres d'entrée ne sont autorisés que dans les clauses WHERE et HAVING et vous ne pouvez pas utiliser de paramètres pour la clause ORDER BY. Ou si je reformule, vous ne pouvez pas utiliser de paramètres pour les colonnes, mais uniquement les valeurs. Alors, soit:

  • Ayez autant de requêtes nommées que possible d'ordre de tri
  • Concaténer la chaîne de commande à la chaîne de requête 
  • Utiliser des requêtes de critères
24
Pascal Thivent

Essayez de stocker la requête nommée sans la clause order by, en récupérant la chaîne de requête et en ajoutant les éléments de la clause order by au moment de l'exécution.

Brian Fields l'expliquait dans son blog: http://brainfields.blogspot.com/2009/08/order-by-in-in-hibernate-named-queries.html

J'ai emballé l'idée pour mon projet:

private static final Pattern badQueryPattern = Pattern.compile("[^\\p{ASCII}]*");

public static String getNamedQueryString(EntityManager em, String queryName) throws SQLException {
    Query tmpQuery = em.createNamedQuery(queryName);
    SQLQuery sqlQuery = tmpQuery.unwrap(SQLQuery.class);
    String queryString = sqlQuery.getQueryString();
    if (badQueryPattern.matcher(queryString).matches()) {
        throw new SQLException("Bad query string.");
    }

    return queryString;
}


public static Query getNamedQueryOrderedBy(EntityManager em, String queryName, Map<String, Boolean> columnNames) throws SQLException {

    StringBuilder sb = new StringBuilder();
    sb.append(ORDER_BY_CLAUSE_START);

    int limit = columnNames.size();
    int i = 0;
    for (String columnName: columnNames.keySet()) {
        sb.append(columnName);

        if (columnNames.get(columnName))
            sb.append(" ASC");
        else
            sb.append(" DESC");

        if (i != (limit - 1)) {
            sb.append(", \n");
        }
    }
    Query jpaQuery = em.createNativeQuery( getNamedQueryString(em, queryName)
                + sb.toString() 
                );

    return jpaQuery;
}
6
SaSConsul

Vous voudrez peut-être limiter le champ de tri à ceux que vous avez dans votre modèle. Dans mon projet, je l'ai fait statiquement:

public static boolean isColumnName(Object domain, String columnName) {
    Field[] fields = domain.getClass().getDeclaredFields();
    for (Field field : fields) {
        Annotation[] annotations = field.getAnnotations();
        for (Annotation annotation : annotations) {
            if (annotation instanceof Column) {
                Column column = (Column) annotation;
                String foundColumnName;
                if (column.name() != null && !column.name().isEmpty()) {
                    foundColumnName = column.name();
                } else {
                    foundColumnName = field.getName();
                }
                if (columnName.toUpperCase().equals(
                    foundColumnName.toUpperCase())) {
                    return true;
                }
            }
        }
    }
    return false;
}   

En validant le nom du champ sur votre DAL avant de concatter la chaîne dans le jpql ou le hql, vous éviterez l’injection de SQL ou d’autres problèmes

2
CaughtOnNet

Cela peut être fait comme ça

 order by CASE :orderBy
          WHEN 'pato_id' THEN PATO.id
          WHEN 'last_update_dt' THEN PATO.last_update_dt
     END desc

et vous pouvez passer "pato_id" ou "last_update_dt" dans la fonction setString comme ceci

 q.setString("orderBy", "last_update_dt");
 or
 q.setString("orderBy", "pato_id");

Cela fonctionne avec MS SQL Server, pas sûr des autres.

0
Dark Knight

Cela fonctionne pour moi dans MySQL:

ORDER BY CASE :orderby WHEN 0 THEN field_x WHEN 1 THEN field_y ELSE field_z END ASC
0
Diego de la Riva