Вопрос

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

Решение

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

Другие советы

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

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

- Лорен

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

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

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

введите класс java.util.ArrayList для идентификаторов элементов параметра с ожидаемым значением тип класса java.lang.Строка из строки запроса

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

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

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

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

О, и если вы по какой-то причине не можете использовать 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 > size; i++) {
            queryString = queryString.concat(" "+field+" = '"+collection.get(i)+"'");
            if(i > size-1) {
                queryString = queryString.concat(" OR");
            }
        }
        queryString = queryString.concat(" )");
        return queryString;
    }

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

В : идентификаторы вместо того , чтобы В (: идентификаторы) - сработает.

Попробуйте этот код вместо того, который предоставил @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));
}

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top