L'impostazione di un parametro come una lista per un'espressione in
-
21-09-2019 - |
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
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)
-
ho avuto vaso JavaEE così come JPA 2 vaso (javax.persistence * 2 *) nel percorso di classe. Rimosso il JavaEE dal percorso della classe.
-
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);