Vraag Een parameter instellen als een lijst voor een IN-uitdrukking


Telkens wanneer ik probeer een lijst in te stellen als een parameter voor gebruik in een IN-expressie, krijg ik een ongeldige argumentuitzondering. Verschillende berichten op het internet lijken erop te wijzen dat dit mogelijk is, maar het werkt zeker niet voor mij. Ik gebruik Glassfish V2.1 met Toplink.

Heeft iemand anders dit kunnen laten werken, zo ja, hoe?

hier is een voorbeeldcode:

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

en het relevante gedeelte van de stacktracering:

java.lang.IllegalArgumentException: U hebt geprobeerd een waarde in te stellen van typeklasse java.util.Arrays $ ArrayList voor parameteraccountIds met het verwachte type klasse java.lang.Long van queryreeks SELECT a.accountManager.loginName FROM Account a WHERE a .id IN (: accountIds).
op oracle.toplink.essentials.internal.ejb.cmp3.base.EJBQueryImpl.setParameterInternal (EJBQueryImpl.java:663)
op oracle.toplink.essentials.internal.ejb.cmp3.EJBQueryImpl.setParameter (EJBQueryImpl.java:202)
bij com.corenap.newtDAO.ContactDaoBean.getNotificationAddresses (ContactDaoBean.java:437)
bij sun.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
bij sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:39)
bij sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:25)
op java.lang.reflect.Method.invoke (Method.java:597)
bij com.sun.enterprise.security.application.EJBSecurityManager.runMethod (EJBSecurityManager.java:1011)
bij com.sun.enterprise.security.SecurityUtil.invoke (SecurityUtil.java:175)
bij com.sun.ejb.containers.BaseContainer.invokeTargetBeanMethod (BaseContainer.java:2920)
bij com.sun.ejb.containers.BaseContainer.intercept (BaseContainer.java:4011)
bij com.sun.ejb.containers.EJBObjectInvocationHandler.invoke (EJBObjectInvocationHandler.java:203)
... 67 meer

21
2017-10-12 21:37


oorsprong


antwoorden:


Je JPQL is ongeldig, verwijder de haakjes

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
2017-11-01 13:58



Ik vond het antwoord, het aanbieden van een lijst als een parameter wordt niet ondersteund in JPA 1.0; het wordt echter ondersteund in JPA 2.0.

De standaard persistentieprovider voor Glassfish v2.1 is Toplink die JPA 1.0 implementeert, om JPA 2.0 te krijgen, hebt u EclipseLink nodig, de standaardinstelling voor het Glassfish v3-voorbeeld of kan worden aangesloten op v2.1.

- Loren


19
2017-10-13 16:48



Ik hoop dat dit iemand helpt. Ik ben met het probleem geconfronteerd en heeft het volgende opgelost (met behulp van eclipselink 2.2.0)

  1. Ik had een JavaEE-pot en jpa 2-jar (javax.persistence * 2 *) in het klassenpad. De JavaEE van het klassenpad verwijderd.

  2. Ik gebruikte zoiets " idItm IN ( :itemIds ) " die de uitzondering gooide:

typ klasse java.util.ArrayList voor parameteritems met verwacht   type klasse java.lang.String from query string

Oplossing: Ik heb zojuist de in-toestand gewijzigd in " idItm IN :itemIds ", d.w.z. ik heb de haakjes verwijderd ().


9
2017-07-07 10:30



Simpel gezegd, de parameter zal List zijn en ingesteld zoals

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

Dit werkt voor JPA 1.0


3
2017-07-25 06:10



Oh, en als je om een ​​of andere reden EclipseLink niet kunt gebruiken, dan is hier een methode die je kunt gebruiken om de benodigde bits aan je vraag toe te voegen. Plaats de resulterende tekenreeks in uw zoekopdracht waar u "a.id IN (: ids)" zou plaatsen.



     /** 
     /* @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
2018-03-17 20:39



Gebruik in plaats daarvan NamedQuery:

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

Voeg de benoemde vraag toe aan uw entiteit

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

0
2018-03-24 17:18



Probeer deze code in plaats van die door @Szymon Tarnowski wordt geleverd om de OF-lijst toe te voegen. waarschuwing als u echter honderden ID's heeft, kunt u de limiet die van toepassing is op de maximale lengte van een query onderbreken.

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

Om dit te 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));
}

Welke gaf output:     AND (myfield = '122' OF myfield = '132' OF myfield = '112')


-1
2017-07-25 01:33



U kunt ook deze syntaxis proberen.

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

En zet in vraag, "Select * from Class where field in " + Class.generateCollection(list);


-3
2017-11-01 13:37