2010-11-08 3 views
12

Salut quelqu'un peut me montrer à la façon dont nous pouvons passer une commande par clause comme paramètre nommé à hQPDHibernate Nommé ordre de requête par le paramètre

Ex:

Travaux:

select tb from TransportBooking as tb 

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

ne fonctionne pas :

select tb from TransportBooking as tb 

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

Répondre

18

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

  • ont autant le nom des requêtes que les ordres de tri possibles
  • concaténer la chaîne de commande à la chaîne de requête
  • Utilisez criteria
+0

Oui merci pour cette API Criteria est la solution. Hibernate s'avère être un ORM très limité. –

+0

Il y a une nouvelle et [possibilité intéressante] (https://stackoverflow.com/a/43900567/5483217) depuis JPA 2.1 – toKrause

6

Essayez le stockage de la requête nommée sans l'ordre by clause, obtention de la chaîne de requête et ajout des commandes order by clause au moment de l'exécution.

Brian Fields a expliqué dans son blog: http://brainfields.blogspot.com/2009/08/order-by-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; 
} 
+1

Nice. Pour JPA 2 avec Hibernate 4, j'utilise 'org.hibernate.Query sqlQuery = tmpQuery.unwrap (org.hibernate.Query.class);' pour éviter 'java.lang.ClassCastException: org.hibernate.internal.QueryImpl ne peut pas être cast à org.hibernate.SQLQuery'. – Arjan

1

Vous pouvez 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; 
} 

Validation le nom du champ sur vous DAL avant concat la chaîne dans la JPQL ou hQPD vous éviterez sql injection ou d'autres problèmes

0

Il 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 celui-ci

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

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

+0

Donc, ce n'est pas une solution SQL générique – SaSConsul

+0

Eh bien, j'ai donné une idée, si ça aide, bon. Sinon, il va certainement aider les utilisateurs de SQL Server. –

Questions connexes