Установка параметра в виде списка для выражения IN - PullRequest
23 голосов
/ 13 октября 2009

Всякий раз, когда я пытаюсь установить список в качестве параметра для использования в выражении IN, я получаю исключение недопустимого аргумента. Различные посты в Интернете, кажется, указывают на то, что это возможно, но это, конечно, не работает для меня. Я использую Glassfish V2.1 с Toplink.

Кто-нибудь еще смог заставить это работать, если да, то как?

вот пример кода:

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

и соответствующая часть трассировки стека:

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

Ответы [ 9 ]

37 голосов
/ 01 ноября 2011

Ваш JPQL недействителен, снимите скобки

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();
20 голосов
/ 13 октября 2009

Я нашел ответ, предоставив список в качестве параметра, не поддерживается в JPA 1.0; однако это поддерживается в JPA 2.0.

Поставщиком персистентности по умолчанию для Glassfish v2.1 является Toplink, который реализует JPA 1.0, для получения JPA 2.0 необходим EclipseLink, который является значением по умолчанию для предварительного просмотра Glassfish v3 или может быть подключен к v2.1.

- Loren

10 голосов
/ 07 июля 2011

Надеюсь, это кому-нибудь поможет. Я столкнулся с проблемой и сделал следующее, чтобы решить (используя eclipselink 2.2.0)

  1. У меня был JavaEE jar, а также jpa 2 jar (javax.persistence * 2 *) в пути к классам. Удален JavaEE из пути к классам.

  2. Я использовал что-то вроде " idItm IN ( :itemIds ) ", которое выдавало исключение:

класс типа java.util.ArrayList для параметра ItemIds с ожидаемым тип класса java.lang.String из строки запроса

Решение: Я только что изменил условие на " idItm IN :itemIds ", то есть снял скобки ().

3 голосов
/ 25 июля 2013

Просто параметр будет List и будет установлен как

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

Это работает для JPA 1.0

0 голосов
/ 29 января 2019

IN: идентификаторы вместо IN (: идентификаторы) - будут работать.

0 голосов
/ 24 марта 2015

Используйте взамен NamedQuery:

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

Добавить именованный запрос к вашей сущности

@NamedQuery(name = "Account.findByIdList", query = "SELECT a.accountManager.loginName FROM Account a WHERE a.id IN :ids")
0 голосов
/ 25 июля 2012

Попробуйте этот код вместо того, который предоставлен @Szymon Tarnowski, чтобы добавить список ИЛИ. предупреждение если у вас есть сотни идентификаторов, вы можете нарушить любой установленный предел в отношении максимальной длины запрос.

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

Чтобы проверить это:

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

Который дал вывод: И (myfield = '122' ИЛИ ​​myfield = '132' ИЛИ ​​myfield = '112')

0 голосов
/ 01 ноября 2011

Вы также можете попробовать этот синтаксис.

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

И положить в запрос, "Select * from Class where field in " + Class.generateCollection(list);

0 голосов
/ 17 марта 2010

Да, и если по какой-то причине вы не можете использовать EclipseLink, то вот метод, который вы можете использовать, чтобы добавить необходимые биты в ваш запрос. Просто вставьте полученную строку в ваш запрос, где вы бы поместили «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 &gt size; i++) {
            queryString = queryString.concat(" "+field+" = '"+collection.get(i)+"'");
            if(i &gt size-1) {
                queryString = queryString.concat(" OR");
            }
        }
        queryString = queryString.concat(" )");
        return queryString;
    }
...