Domanda

Ogni volta che provo a impostare una lista come parametro per l'uso in un nell'espressione ottengo un'eccezione argomento illegale. Vari messaggi su internet sembrano indicare che questo è possibile, ma non è certamente a lavorare per me. Sto usando Glassfish V2.1 con TopLink.

Qualcuno ha altro stato in grado di farlo funzionare, se sì, come?

Ecco qualche esempio di codice:

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

e la parte rilevante l'analisi dello stack:

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
È stato utile?

Soluzione

Il tuo JPQL non è valido, rimuovere le staffe

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

Altri suggerimenti

Ho trovato la risposta, fornendo un elenco come parametro non è supportato in JPA 1.0; tuttavia, è supportato in JPA 2.0.

Il provider di persistenza di default per Glassfish v2.1 è Toplink che implementa JPA 1.0, per ottenere JPA 2.0 è necessario EclipseLink che è l'impostazione predefinita per la v3 anteprima Glassfish o può essere collegato a v2.1.

- Loren

Spero che questo aiuti qualcuno. Ho affrontato il problema e ho il seguente per risolvere (utilizzando EclipseLink 2.2.0)

  1. ho avuto vaso JavaEE così come JPA 2 vaso (javax.persistence * 2 *) nel percorso di classe. Rimosso il JavaEE dal percorso della classe.

  2. Stavo usando qualcosa come " idItm IN ( :itemIds ) " che è stato gettando eccezione:

  

java.util.ArrayList tipo di classe per ItemIDs parametri con previsto   tipo di classe java.lang.String dalla stringa di query

. Soluzione: Ho appena cambiato il in condizione di " idItm IN :itemIds ", vale a dire ho rimosso le parentesi ()

Semplicemente, il parametro sarà List e impostarlo come

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

Questo funziona per JPA 1.0

Oh, e se non è possibile utilizzare EclipseLink per qualche ragione, allora qui è un metodo che è possibile utilizzare per aggiungere i bit necessari alla tua richiesta. Basta inserire la stringa risultante nella vostra query in cui si sarebbe messo "a.id IN (: id)".



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

Usa NamedQuery invece:

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

Aggiungere la query di nome al tuo entità

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

IN: ids al posto di IN (: id) - lavorerà

.

Prova questo codice al posto di quello fornito da @Szymon Tarnowski per aggiungere la lista OR .. avviso se si dispone di centinaia di ID, però, si potrebbe rompere qualsiasi limite è a posto per quanto riguarda la lunghezza massima di una query.

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

Per verificare questa:

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

Il che ha dato in uscita:     E (MyField = '122' OR myfield = '132' OR myfield = '112')

È anche possibile provare questa sintassi.

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

E mettere in interrogazione, "Select * from Class where field in " + Class.generateCollection(list);

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top