Estoy tratando de escribir una parte dinámica de consulta HQL sin tener que recurrir a la API de Criterios por varias razones. Quería saber si hay una manera fácil de corto circuito, donde la restricción de uso de HQLs expresiones. Por ejemplo, aquí es el de la consulta original que funciona bien:

SELECT customer 
FROM Customer as customer 
INNER JOIN customer.profile as profile 
WHERE profile.status IN :statusCodes
AND   profile.orgId IN :orgIds

StatusCodes es una lista de Cadenas y orgIds es una lista de Enteros. Sin embargo, cualquiera de las dos es opcional y no debe restringir si se pasa un valor null en lugar de una colección. He tratado de realizar esta así:

SELECT customer 
FROM Customer as customer 
INNER JOIN customer.profile as profile 
WHERE (:statusCodes IS NULL OR profile.status IN :statusCodes)
AND   (:orgIds IS NULL OR profile.orgId IN :orgIds)

Esto no funciona, lamentablemente, pero hay otro enfoque que podría funcionar, ya sea con el uso de diferentes expresiones o pasar en los valores predeterminados?

EDIT: para que quede claro que yo estoy buscando una manera de utilizar un NamedQuery, no de forma dinámica la construcción de la consulta de cualquier manera.

SOLUCIÓN: he utilizado el extra de los parámetros de consulta para lograrlo. He creado dos métodos de ayuda:

private void setRequiredParameter(TypedQuery<?> query, String name, Object value) {
    query.setParameter(name, value);
}

private void setOptionalParameter(TypedQuery<?> query, String name, Object value) {
    query.setParameter(name, value);
    query.setParameter(name + "Optional", value == null ? 1 : 0);
}

Y la consulta así:

SELECT customer 
        FROM Customer as customer 
        INNER JOIN  customer.profile as profile 
        WHERE (:statusCodesOptional = 1 OR profile.status IN :statusCodes)
        AND (:orgIdsOptional = 1 OR profile.orgId  IN :orgIds)
InformationsquelleAutor ant-depalma | 2012-05-17

3 Comentarios

  1. 2

    Si usted absolutamente debe evitar consultas dinámicas, puede hacerlo a expensas de dos parámetros adicionales:

    SELECT customer 
      FROM Customer AS customer 
      JOIN customer.profile AS profile 
     WHERE (profile.status IN :statusCodes OR :statusCodeCount = 0)
       AND (profile.orgId IN :orgIds OR :orgIdCount = 0)

    En el código Java, a continuación, hacer algo como:

    session.getNamedQuery("your.query.name")
           .setParameterList("statusCodes", statusCodes)
           .setParameter("statusCodeCount", statusCodes.length)
           .setParameterList("orgIds", orgIds)
           .setParameter("orgIdCount", orgIds.length);

    Debe asegurarse de que las matrices son de longitud cero en lugar de null o suministro adicional si los cheques para manejar null escenario.

    Todo lo que dijo, HQL es realmente mejor para bien definido (por ejemplo, estática) de las consultas. Usted puede trabajar en torno a parámetros dinámicos, usted no será capaz de trabajar en torno a dinámicas de clasificación.

    • Gracias, esto es lo que se sospecha, aunque estoy todavía con la esperanza de que hay una manera de utilizar expresiones para evitar que los parámetros extra.
    • No hay – no para las listas. Hibernación del procesador de consultas tiene que hacer un poco de magia detrás de las escenas a las listas de apoyo (en concreto, contar el número de elementos y generar el correspondiente número de parámetros posicionales en SQL resultante) por lo que pasa en <code>null</código de> no es una opción.
    • ¿Qué acerca de la inyección de SQL posibilidad?
  2. 5

    Mi sugerencia es poner todos los parámetros en un mapa y crear la consulta dinámica, después de la construcción antes de la ejecución de establecer todos los parámetros requeridos por la consulta tomando valores desde el mapa:

    Map<String, Object> pars = new HashMap<String,Object>();
    pars.put("statusCodes", statusCodes);
    pars.put("orgIds", orgIds);
    
    StringBuilder b = "SELECT customer FROM Customer as customer INNER JOIN customer.profile as profile where 1 = 1";
    if (statusCodes != null) {
      b.append(" and profile.status in :statusCodes");
    }
    if (orgIds != null) {
      b.append(" and profile.orgId in :statusCodes");
    }
    
    ...
    
    Query q = session.createQuery(b.toString());
    
    ...
    
    for (String p : q.getNamedParameters()) {
      q.setParameter(p, pars.get(p));
    }

    Por supuesto que algunas de las mejoras son necesarias, por ejemplo, lanzar la excepción cuando los parámetros no es de uso escrito parámetro si la complejidad es más grande que un par de parámetros sencillos y así sucesivamente.

    • ¿Qué acerca de la inyección de SQL probabilidad?
    • No hay ninguna posibilidad para la inyección de sql en este caso, se maneja como un parámetro y, como tal, tiene su contenido se escapó.
    • Es claro ahora, gracias.
  3. 0

    Tendrás que generar su consulta de forma dinámica:

    StringBuilder hql = 
        new StringBuilder("SELECT customer FROM Customer as customer INNER JOIN customer.profile as profile where 1 = 1")
    if (statusCodes != null) {
        hql.append(" and profile.status IN :statusCodes");
    }
    if (orgIds != null) {
        hql.append(" and profile.orgId IN :orgIds");
    }

    Por supuesto, usted también tendrá que configurar los parámetros para la consulta sólo si son no nulos.

    • Gracias, pero estoy tratando de evitar escribir cualquier consultas dinámicas. Quiero que las consultas a vivir en el .hbm archivos debido a que algunos inevitablemente necesitará ser ajustado o convertir a los nativos de las consultas. Así que debe haber alguna forma de mantenerlas como consultas con nombre en lugar de forma dinámica la construcción de ellos.
    • Entonces, AFAIK, usted necesitará 4 consultas diferentes: uno para cada combinación posible (null-null, notnull null, null notnull, notnull-notnull). Sólo tiene la esperanza de que usted no necesita un tercer parámetro. Tenga en cuenta que yo no veo cómo el cambio de la estática HQL para SQL en un archivo xml es mucho más fácil que cambiar la dinámica HQL a SQL dinámico en el archivo Java.
    • El beneficio proviene del hecho de que la aplicación no necesita saber si el nombre de una consulta hql o sql. Simplemente se pueden intercambiarse en un archivo xml por un dba, incluso. Y estoy buscando a uso O condiciones para evitar tener varias consultas.

Dejar respuesta

Please enter your comment!
Please enter your name here