web-dev-qa-db-fra.com

Définition d'un paramètre en tant que liste pour une expression IN

Chaque fois que j'essaie de définir une liste en tant que paramètre à utiliser dans une expression IN, je reçois une exception d'argument Illegal. Divers articles sur Internet semblent indiquer que c'est possible, mais cela ne fonctionne certainement pas pour moi. J'utilise Glassfish V2.1 avec Toplink. 

Quelqu'un d'autre a-t-il réussi à faire fonctionner cela? Si oui, comment?

voici un exemple de code:

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

et la partie pertinente de la trace de pile:

 Java.lang.IllegalArgumentException: vous avez tenté de définir une valeur de type class Java.util.Arrays $ ArrayList pour le paramètre accountIds avec le type attendu de classe Java.lang.Long à partir de la chaîne de requête SELECT a.accountManager.loginName FROM compte a WHERE a.id IN (: accountIds) .
 à Oracle.toplink.essentials.internal.ejb.cmp3.base.EJBQueryImpl.setParameterInternal (EJBQueryImpl.Java:663) 
 sur Oracle.toplink.essentials.internal le 
 à Sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.Java:39) 
 à Sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.Java:25) 
 à. Méthode.Java:597)
au com.Sun.enterprise.security.application.EJBSecurityManager.runMethod (EJBSecurityManager.Java:1011) 
 À com.Sun.ent erprise.security.SecurityUtil.invoke (SecurityUtil.Java:175) 
 sur com.Sun.ejb.containers.BaseContainer.invokeTargetBeanMethod (BaseContainer.Java:2920) 
 sur com.Sun.ejb.containers. intercept (BaseContainer.Java:4011) 
 sur com.Sun.ejb.containers.EJBObjectInvocationHandler.invoke (EJBObjectInvocationHandler.Java:203) 
... 67 autres 
22
perilandmishap

Votre JPQL n'est pas valide, supprimez les crochets

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

J'ai trouvé la réponse, fournir une liste en tant que paramètre n'est pas pris en charge dans JPA 1.0; Cependant, il est pris en charge dans JPA 2.0. 

Le fournisseur de persistance par défaut de Glassfish v2.1 est Toplink, qui implémente JPA 1.0. Pour obtenir JPA 2.0, vous avez besoin d’EclipseLink, qui est la valeur par défaut pour la prévisualisation de Glassfish v3.

- Loren

20
perilandmishap

J'espère que cela aide quelqu'un. J'ai fait face au problème et fait ce qui suit pour résoudre (en utilisant eclipselink 2.2.0)

  1. J'avais jar JavaEE ainsi que jpa 2 jar (javax.persistence * 2 *) dans le chemin de classe. Suppression de JavaEE du chemin de classe.

  2. J'utilisais quelque chose comme " idItm IN ( :itemIds ) " qui lançait l'exception:

tapez la classe Java.util.ArrayList pour le paramètre itemIds avec attendu type de classe Java.lang.String à partir de la chaîne de requête

Solution: Je viens de changer la condition in en " idItm IN :itemIds ", c'est-à-dire que j'ai supprimé les crochets ().

10
dillip

Simplement, le paramètre sera List et le définira comme 

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

Cela fonctionne pour JPA 1.0

3
Abhishek Chatterjee

IN: ids au lieu de IN (: ids) - fonctionnera.

0
Atul Jain

Oh, et si vous ne pouvez pas utiliser EclipseLink pour une raison quelconque, voici une méthode que vous pouvez utiliser pour ajouter les bits nécessaires à votre requête. Insérez simplement la chaîne résultante dans votre requête où vous mettriez "a.id IN (: 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;
    }
0
perilandmishap

Utilisez NamedQuery à la place:

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

Ajouter la requête nommée à votre entité

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