Java Hibernate按参数命名查询顺序

Java Hibernate按参数命名查询顺序,java,hibernate,orm,hql,sql-order-by,Java,Hibernate,Orm,Hql,Sql Order By,有人能告诉我如何将ORDERBY子句作为命名参数传递给HQL吗 有效的示例: select tb from TransportBooking as tb and TIMESTAMP(tb.bookingDate, tb.bookingTime) >= current_timestamp() order by tb.bookingDate 不起作用的示例: select tb from TransportBooking as tb and TIMESTAMP(tb.bookingDat

有人能告诉我如何将ORDERBY子句作为命名参数传递给HQL吗

有效的示例:

select tb from TransportBooking as tb

and TIMESTAMP(tb.bookingDate, tb.bookingTime) >= current_timestamp() order by tb.bookingDate
不起作用的示例:

select tb from TransportBooking as tb

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

不支持,仅允许在
WHERE
具有
子句的情况下输入参数,并且不能将参数用于
ORDER BY
子句。或者,如果我重新措辞,您不能对列使用参数,只能使用值。因此,要么:

  • 拥有尽可能多的命名查询排序顺序
  • 将排序字符串连接到查询字符串
  • 使用条件查询

尝试在不使用ORDERBY子句的情况下存储命名查询,获取查询字符串并在运行时添加ORDERBY子句片段

Brian Fields在他的博客中解释了这一点:

我已经为我的项目打包了想法:

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;
}
private static final Pattern badQueryPattern=Pattern.compile(“[^\\p{ASCII}]*”);
公共静态字符串getNamedQueryString(EntityManager em,字符串queryName)引发SQLException{
Query tmpQuery=em.createNamedQuery(queryName);
SQLQuery SQLQuery=tmpQuery.unwrap(SQLQuery.class);
字符串queryString=sqlQuery.getQueryString();
if(badQueryPattern.matcher(queryString.matches()){
抛出新的SQLException(“错误的查询字符串”);
}
返回查询字符串;
}
公共静态查询getNamedQueryOrderedBy(EntityManager em、字符串queryName、映射列名)引发SQLException{
StringBuilder sb=新的StringBuilder();
sb.追加(按条款顺序开始);
int limit=columnNames.size();
int i=0;
for(字符串columnName:columnNames.keySet()){
附加某人(姓名);
if(columnNames.get(columnName))
某人附加(“ASC”);
其他的
某人附加(“说明”);
如果(i!=(限制-1)){
sb.追加(“,\n”);
}
}
Query jpaQuery=em.createNativeQuery(getNamedQueryString(em,queryName)
+(某人)
);
返回jpaQuery;
}

您可能希望将排序字段限制为模型中的字段。在我的项目中,我静态地完成了这项工作:

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

在将字符串导入jpql或hql之前验证DAL上的字段名,这样可以避免sql注入或进一步的问题

 order by CASE :orderBy
          WHEN 'pato_id' THEN PATO.id
          WHEN 'last_update_dt' THEN PATO.last_update_dt
     END desc
 q.setString("orderBy", "last_update_dt");
 or
 q.setString("orderBy", "pato_id");
您可以传递“pato_id”或“last_update_dt” 在像这样的setString函数中

 order by CASE :orderBy
          WHEN 'pato_id' THEN PATO.id
          WHEN 'last_update_dt' THEN PATO.last_update_dt
     END desc
 q.setString("orderBy", "last_update_dt");
 or
 q.setString("orderBy", "pato_id");

这适用于MS SQL Server,但不确定其他服务器。

这适用于我在MySQL中的情况:

ORDER BY CASE :orderby WHEN 0 THEN field_x WHEN 1 THEN field_y ELSE field_z END ASC

是的,非常感谢API是解决方案。Hibernate被证明是一个非常有限的ORM。有一个新的和自JPA2.1Nice以来的ORM。对于带有Hibernate4的JPA2,我使用
org.Hibernate.querySQLQuery=tmpQuery.unwrap(org.Hibernate.Query.class)
为了避免
java.lang.ClassCastException:org.hibernate.internal.QueryImpl不能强制转换为org.hibernate.SQLQuery
。因此,这不是一个通用的SQL解决方案。好吧,我提出了一个想法,如果它有帮助的话,很好。否则,它肯定会帮助SQL Server用户。