Подтвердить что ты не робот

Установка параметра в виде списка для выражения IN

Всякий раз, когда я пытаюсь установить список в качестве параметра для использования в выражении 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
4b9b3361

Ответ 1

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

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

- Loren

Ответ 2

Ваш 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();

Ответ 3

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

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

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

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

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

Ответ 4

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

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

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

Ответ 5

О, и если вы не можете использовать 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;
    }

Ответ 6

Вместо этого используйте 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")

Ответ 7

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

Ответ 8

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

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

Который дал результат:   AND (myfield = '122' ИЛИ ​​myfield = '132' ИЛИ ​​myfield = '112')

Ответ 9

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

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