2010-11-08 11 views
12

Cześć może ktoś mi punkt w jaki sposób możemy przekazać zamówienie przez klauzuli jako parametru nazwanego do HQLHibernate Nazwany Zapytanie Zamówienie parametrem

Ex:

działa:

select tb from TransportBooking as tb 

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

nie działa :

select tb from TransportBooking as tb 

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

Odpowiedz

18

Nieobsługiwane, parametry wejściowe są dozwolone tylko w WHERE i HAVING i nie można używać parametrów dla klauzuli ORDER BY. Lub jeśli zmienię rephrazę, nie można używać parametrów dla kolumn, tylko wartości. Więc, albo:

  • mieć tyle nazwie kwerendy jako możliwych zleceń sortowania
  • złączyć strunowe zamawiania do łańcucha zapytania
  • kryteria użyć kwerendy
+0

Tak, dziękuję za to, że API Kryteriów jest rozwiązaniem. Hibernate okazuje się być bardzo ograniczoną ORM. –

+0

Istnieje nowa i [interesująca możliwość] (https://stackoverflow.com/a/43900567/5483217) od wersji JPA 2.1 – toKrause

6

Spróbuj przechowywania nazwie zapytanie bez zlecenia klauzula uzyskująca ciąg zapytania i dodająca elementy porządku według klauzuli w czasie wykonywania.

Brian Fields wyjaśnił w swoim blogu: http://brainfields.blogspot.com/2009/08/order-by-in-hibernate-named-queries.html

Mam zapakowanego pomysł się do mojego projektu:

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. W przypadku JPA 2 z Hibernate 4 używam 'org.hibernate.Query sqlQuery = tmpQuery.unwrap (org.hibernate.Query.class);', aby uniknąć 'java.lang.ClassCastException: org.hibernate.internal.QueryImpl nie można obsaczyć do org.hibernate.SQLQuery'. – Arjan

1

Możesz chcieć ograniczyć pole sortowania do tych, które masz w swoim Model. W moim projekcie Zrobiłem to statycznie:

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

Members nazwę pola na ciebie DAL przed concat ciąg do JPQL lub HQL będzie można uniknąć SQL Injection czy dalsze problemy

0

Można to zrobić jak ten

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

i można przekazać "pato_id" lub "last_update_dt" w funkcji setString tak

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

Działa z serwerem MS SQL Server, nie jest pewien innych.

+0

To nie jest ogólne rozwiązanie SQL – SaSConsul

+0

Cóż, dałem pomysł, jeśli to pomaga, dobrze. W przeciwnym razie z pewnością pomoże to użytkownikom SQL Server. –

Powiązane problemy