Frage

Immer wenn ich versuche, eine Liste als Parameter für die Verwendung in einem Ausdruck festzulegen, erhalte ich eine illegale Argument -Ausnahme. Verschiedene Beiträge im Internet scheinen darauf hinzudeuten, dass dies möglich ist, aber es funktioniert sicherlich nicht für mich. Ich verwende Glassfish v2.1 mit TopLink.

Hat jemand anderes dies zum Laufen bringen, wenn ja, wie?

Hier ist ein Beispielcode:

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

und der relevante Teil der Stapelspur:

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
War es hilfreich?

Lösung

Ihr JPQL ist ungültig, entfernen Sie die Klammern

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

Andere Tipps

Ich fand die Antwort, dass in JPA 1.0 eine Liste als Parameter nicht unterstützt wird. Es wird jedoch in JPA 2.0 unterstützt.

Der Standard -Persistenzanbieter für Glassfish v2.1 ist TopLink, der JPA 1.0 implementiert, um JPA 2.0 zu erhalten. Sie benötigen EclipSelink.

- Loren

Hoffe das hilft jemandem. Ich habe dem Problem konfrontiert und habe Folgendes durchgeführt, um es zu lösen (mit EclipSelink 2.2.0)

  1. Ich hatte Javaee Jar sowie JPA 2 Jar (Javax.Persistence*2*) im Klassenpfad. Entfernte den Javaee vom Klassenpfad.

  2. Ich habe so etwas verwendet " idItm IN ( :itemIds ) " Welches war die Ausnahme:

Geben Sie die Klasse java.util.ArrayList für Parameter itemIDs mit erwarteter Klassentyp Java.lang.String aus der Abfragezeichenfolge ein

Lösung: Ich habe gerade den Zustand in der Bedingung geändert zu " idItm IN :itemIds ", dh ich habe die Klammern entfernt ().

Der Parameter wird einfach eine Liste sein und ihn als festlegen

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

Dies funktioniert für JPA 1.0

Oh, und wenn Sie EclipSelink aus irgendeinem Grund nicht verwenden können, können Sie hier eine Methode verwenden, um die benötigten Bits Ihrer Abfrage hinzuzufügen. Fügen Sie einfach die resultierende Zeichenfolge in Ihre Abfrage ein, in der Sie "A.ID in (: ids)" einfügen würden.



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

Verwenden Sie stattdessen "NamingQuery":

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

Fügen Sie die benannte Abfrage zu Ihrem Unternehmen hinzu

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

In: IDS Anstatt von In (: ids) - wird funktionieren.

Versuchen Sie diesen Code anstelle des von @szymon tarnowski gelieferten Code, um die oder Liste hinzuzufügen. Warnung Wenn Sie jedoch Hunderte von IDs haben, können Sie die Grenze in Bezug auf die maximale Länge einer Abfrage brechen.

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

Um dies zu testen:

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

Die Ausgabe ergab: und (myfield = '122' oder myfield = '132' oder myfield = '112')

Sie können diese Syntax auch ausprobieren.

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

Und in Frage gestellt, "Select * from Class where field in " + Class.generateCollection(list);

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top