Question

Chaque fois que je tente de définir une liste en tant que paramètre pour une utilisation dans une expression IN je reçois une exception d'argument illégal. Divers messages sur Internet semblent indiquer que cela est possible, mais il est certainement ne fonctionne pas pour moi. J'utilise Glassfish v2.1 avec Toplink.

Quelqu'un at-il pu obtenir que cela fonctionne, si oui, comment?

est ici quelques exemples 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 correspondante de la trace de pile:

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
Était-ce utile?

La solution

Votre JPQL est non valide, retirez 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();

Autres conseils

J'ai trouvé la réponse, en fournissant une liste en tant que paramètre 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 pour Glassfish v2.1 est Toplink qui implémente JPA 1.0, pour obtenir JPA 2.0 dont vous avez besoin EclipseLink qui est la valeur par défaut pour le Glassfish v3 preview ou peut être branché sur v2.1.

- Loren

Espérons que cela aide quelqu'un. J'ai fait face à la question et ne suit pour résoudre (en utilisant EclipseLink 2.2.0)

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

  2. J'utilisais quelque chose comme " idItm IN ( :itemIds ) " qui a été jeter l'exception:

  

java.util.ArrayList de classe de type pour le paramètre itemID avec prévu   type de java.lang.String de classe de chaîne de requête

Solution:. Je viens de modifier la condition dans " idItm IN :itemIds ", à savoir que je supprimé les crochets ()

Il suffit, le paramètre sera la liste et le définir comme

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

Cela fonctionne pour JPA 1.0

Oh, et si vous ne pouvez pas utiliser EclipseLink pour une raison alors voici une méthode que vous pouvez utiliser pour ajouter les bits nécessaires à votre requête. Il suffit d'insérer 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;
    }

Utilisez NamedQuery au lieu:

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

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

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

: ids au lieu de (: ids) - œuvreront

.

Essayez ce code au lieu de celui fourni par @Szymon Tarnowski ajouter la liste OU .. avertissement si vous avez des centaines d'ID cependant, vous pourriez casser tout ce qui limite est en place en ce qui concerne la longueur max d'une requête.

/**
 * @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;
}

Pour tester ceci:

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

Ce qui a donné la sortie:     ET (myfield = '122' OR myfield = '132' OR myfield = '112')

Vous pouvez également essayer cette syntaxe.

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

Et mettre en requête, "Select * from Class where field in " + Class.generateCollection(list);

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top