Siempre que se intenta establecer una lista como un parámetro para usar en una expresión puedo obtener una Ilegales argumento de la excepción. Varias publicaciones en internet parecen indicar que esto es posible, pero ciertamente no es trabajo para mí. Estoy usando el servidor Glassfish V2.1 con Toplink.

Ha nadie ha sido capaz de conseguir que esto funcione, si es así, cómo?

he aquí un ejemplo de código:

List<String> logins = em.createQuery("SELECT a.accountManager.loginName " +
    "FROM Account a " +
    "WHERE a.id IN (:ids)")
    .setParameter("ids",Arrays.asList(new Long(1000100), new Long(1000110)))
    .getResultList();

y la parte pertinente de la traza de la pila:

java.lang.IllegalArgumentException: Se han intentado establecer un valor de un tipo de clase de java.util.Matrices de$ArrayList para el parámetro accountIds con el tipo esperado de la clase java.lang.Largo de la cadena de consulta de SELECCIONAR una.accountManager.loginName DE la Cuenta a DONDE.id (:accountIds). 
en oracle.toplink.essentials.internal.ejb.cmp3.base.EJBQueryImpl.setParameterInternal(EJBQueryImpl.java:663) 
en oracle.toplink.essentials.interna.ejb.cmp3.EJBQueryImpl.setParameter(EJBQueryImpl.java:202) 
en com.corenap.newtDAO.ContactDaoBean.getNotificationAddresses(ContactDaoBean.java:437) 
en el sol.reflejar.NativeMethodAccessorImpl.invoke0(Native Method) 
en el sol.reflejar.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
en el sol.reflejar.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
en java.lang.reflejar.Método.invoke(Método.java:597) 
en com.sol.empresa.de seguridad.aplicación.EJBSecurityManager.runMethod(EJBSecurityManager.java:1011) 
en com.sol.empresa.de seguridad.SecurityUtil.invoke(SecurityUtil.java:175) 
en com.sol.ejb.los contenedores.BaseContainer.invokeTargetBeanMethod(BaseContainer.java:2920) 
en com.sol.ejb.los contenedores.BaseContainer.intersección(BaseContainer.java:4011) 
en com.sol.ejb.los contenedores.EJBObjectInvocationHandler.invoke(EJBObjectInvocationHandler.java:203) 
... 67 más 

9 Comentarios

  1. 37

    Su JPQL no es válido, retire los soportes

    List<String> logins = em.createQuery("SELECT a.accountManager.loginName " +
        "FROM Account a " +
        "WHERE a.id IN :ids")
        .setParameter("ids",Arrays.asList(new Long(1000100), new Long(1000110)))
        .getResultList();
    • Por desgracia no tuve el mismo error.. contamos con Java EE 5, por lo tanto, EJB 3.0. A partir de la Especificación: «JSR 220: Enterprise JavaBeans,Versión 3.0 – API de Persistencia Java Sección» veo «En» Expresión requiere corchetes.. pero luego me estaba poniendo IllegalArgumentException cuando ajuste el parámetro como una Lista de<Integer>.. así que estoy usando el terrible hack por debajo de la expansión de los Identificadores en una cadena de ORs (hasta que pueda obtener el adecuado JPA asignaciones en su lugar con una DB de Vista para evitar que).
    • No para mí .setParameter(), he tenido que utilizar setParameterList()
    • ¿Cómo puede una cadena como var ids = "a1","b1",...; pasarse a java función y a su vez para el operador?
    • Eso es porque usted es más probable el uso de Consulta de hibernate y no persistencia de Consulta
  2. 20

    He encontrado la respuesta, proporcionando una lista como parámetro no es compatible con JPA 1.0; sin embargo, se admite en JPA 2.0.

    El valor predeterminado proveedor de persistencia para Glassfish v2.1 es Toplink que implementa JPA 1.0, para obtener JPA 2.0 necesita EclipseLink que es el predeterminado para el servidor Glassfish v3 vista previa o puede ser conectado a v2.1.


    Loren

    • y su JPQL está mal, retire los soportes
    • Mal. Depende de la aplicación con JPA 1.0 implementado por Hibernate es trabajo, pero sin necesidad de soportes.
    • Este solía ser un error en modo de Hibernación: hibernate.atlassian.net/browse/HHH-5126
  3. 10

    Espero que esto ayuda a una. Me he encontrado con el problema e hice lo siguiente para resolver (utilizando eclipselink 2.2.0)

    1. Me había JavaEE jar así como jpa 2 tarro(javax.persistencia*2*) en la ruta de clase. Eliminado el JavaEE de la ruta de clase.

    2. Yo estaba usando algo como " idItm IN ( :itemIds ) " que estaba lanzando una excepción :

    tipo de clase de java.util.ArrayList para el parámetro itemIds con la espera
    tipo de clase de java.lang.Cadena de cadena de consulta

    Solución: acabo de cambiar la condición para " idItm IN :itemIds ", es decir, que me quita el paréntesis ().

    • muchas gracias @dillip usted salvó mi día. Yo sólo tenía que eliminar los paréntesis alrededor de parámetro
  4. 0

    Ah, y si no puede usar EclipseLink, por alguna razón, entonces aquí es un método que puede utilizar para agregar la necesaria bits para su consulta. Sólo tiene que insertar la cadena resultante en la consulta donde se pondría «un.id (:ids)».

    
    
         /** 
         /* @param field The jpql notation for the field you want to evaluate
         /* @param collection The collection of objects you want to test against
         /* @return Jpql that can be concatenated into a query to test if a feild is in a 
         */
    collection of objects
        public String in(String field, List collection) {
            String queryString = new String();
            queryString = queryString.concat(" AND (");
            int size = collection.size();
            for(int i = 0; i > size; i++) {
                queryString = queryString.concat(" "+field+" = '"+collection.get(i)+"'");
                if(i > size-1) {
                    queryString = queryString.concat(" OR");
                }
            }
            queryString = queryString.concat(" )");
            return queryString;
        }
  5. 0

    Uso NamedQuery lugar:

    List<String> logins = em.createNamedQuery("Account.findByIdList").setParameter("ids", Arrays.asList(new Long(1000100), new Long(1000110))).getResultList();

    Agregar el nombre de la consulta a su entidad

    @NamedQuery(name = "Account.findByIdList", query = "SELECT a.accountManager.loginName FROM Account a WHERE a.id IN :ids")
  6. -1

    Probar este código en lugar de la suministrada por @Szymon Tarnowski para agregar la lista O.. advertencia si usted tiene cientos de IDs, aunque, usted puede romper cualquier límite está en su lugar con respecto a la longitud máxima de una consulta.

    /**
     * @param field
     *           The jpql notation for the field you want to evaluate
     * @param collection
     *           The collection of objects you want to test against
     * @return Jpql that can be concatenated into a query to test if a feild is
     *         in a collection of objects
     */
    public static String in(String field, List<Integer> idList) {
      StringBuilder sb = new StringBuilder();
      sb.append(" AND (");
      for(Integer id : idList) {
        sb.append(" ").append(field).append(" = '").append(id).append("'").append(" OR ");
      }
      String result = sb.toString();
      result = result.substring(0, result.length() - 4); //Remove last OR
      result += ")";
      return result;
    }

    Para probar esto:

    public static void main(String[] args) {
      ArrayList<Integer> list = new ArrayList<Integer>();
      list.add(122);
      list.add(132);
      list.add(112);
      System.out.println(in("myfield", list));
    }

    Que dio salida:
    Y ( micampo = ‘122’ O micampo = ‘132’ O micampo = ‘112’)

    • Repita después de mí: «yo nunca uso StringBuilders u otras técnicas similares para construir consultas SQL ya que esto permite la inyección de código SQL. Yo sólo uso declaraciones preparadas y tal.»
    • Gracias por la advertencia sobre posibles vulnerabilidades de SQL @siebz0r. Sin embargo no creo que esto es válido aquí. Declaraciones preparadas no puede ser utilizado como el número de argumentos no son conocidos y, en la versión de JPA no permitir la lista de argumentos. También, los argumentos aquí no son de la opinión del público y son emitidos como Entero objetos.
    • Entiendo los riesgos son limitados, pero aún así, cosas extrañas pueden suceder. java.sql.PreparedStatement puede ser utilizado para tales casos raros. Esta interfaz soporta colecciones como parámetro.
    • No hay manera de hacer que la inyección de SQL con la lista de números de…
  7. -3

    También puede tratar de esta sintaxis.

    static public String generateCollection(List list){
        if(list == null || list.isEmpty())
            return "()";
        String result = "( ";
        for(Iterator it = list.iterator();it.hasNext();){
            Object ob = it.next();
            result += ob.toString();
            if(it.hasNext())
                result += " , ";
        }
        result += " )";
        return result;
    }

    Y puesto en consulta, "Select * from Class where field in " + Class.generateCollection(list);

    • No, No, No. Esta es la voluntad de permitir la inyección de SQL posibilidades.

Dejar respuesta

Please enter your comment!
Please enter your name here