Pregunta

Cada vez que intento establecer una lista como parámetro para usar en una expresión IN, aparece una excepción de argumento ilegal.Varias publicaciones en Internet parecen indicar que esto es posible, pero ciertamente no me funciona.Estoy usando Glassfish V2.1 con Toplink.

¿Alguien más ha podido hacer que esto funcione? De ser así, ¿cómo?

aquí hay un código de ejemplo:

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 relevante del seguimiento de la pila:

java.lang.IllegalArgumentException: You have attempted to set a value of type class java.util.Arrays$ArrayList for parameter accountIds with expected type of class java.lang.Long from query string SELECT a.accountManager.loginName FROM Account a WHERE a.id IN (:accountIds).
at oracle.toplink.essentials.internal.ejb.cmp3.base.EJBQueryImpl.setParameterInternal(EJBQueryImpl.java:663)
at oracle.toplink.essentials.internal.ejb.cmp3.EJBQueryImpl.setParameter(EJBQueryImpl.java:202)
at com.corenap.newtDAO.ContactDaoBean.getNotificationAddresses(ContactDaoBean.java:437)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.sun.enterprise.security.application.EJBSecurityManager.runMethod(EJBSecurityManager.java:1011)
at com.sun.enterprise.security.SecurityUtil.invoke(SecurityUtil.java:175)
at com.sun.ejb.containers.BaseContainer.invokeTargetBeanMethod(BaseContainer.java:2920)
at com.sun.ejb.containers.BaseContainer.intercept(BaseContainer.java:4011)
at com.sun.ejb.containers.EJBObjectInvocationHandler.invoke(EJBObjectInvocationHandler.java:203)
... 67 more
¿Fue útil?

Solución

Su JPQL no es válido, eliminar los corchetes

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();

Otros consejos

he encontrado la respuesta, proporcionando una lista como un parámetro no está soportado en JPA 1.0; sin embargo, se admite en JPA 2.0.

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

- Loren

Espero que esto ayude a alguien.Enfrenté el problema e hice lo siguiente para resolverlo (usando eclipselink 2.2.0)

  1. Tenía el jar JavaEE y el jar jpa 2 (javax.persistence*2*) en la ruta de clase.Se eliminó JavaEE de la ruta de clase.

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

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

Solución:Acabo de cambiar la condición a " idItm IN :itemIds ", es decir.Quité los corchetes ().

Simplemente, el parámetro estará lista y configurarlo como

"...WHERE a.id IN (:ids)")
.setParameter("ids", yourlist)

Esto funciona para JPA 1.0

Ah, y si no se puede utilizar EclipseLink por alguna razón, entonces aquí es un método que puede utilizar para agregar los bits necesarios para su consulta. Sólo tiene que insertar la cadena resultante en su consulta en la que pondría "a.id EN (: 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;
    }

Uso NamedQuery lugar:

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

Añadir la consulta con nombre a su entidad

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

EN: identificadores de en lugar de EN (: IDS) - trabajará

.

Prueba este código en lugar de la suministrada por @Szymon Tarnowski añadir la lista de O .. Advertencia si tiene cientos de identificaciones embargo, es posible 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 (myfield = '122' OR myfield = '132' OR myfield = '112')

También puede probar 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);

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top