it-roy-ru.com

Установка параметра в виде списка для выражения 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: вы попытались установить значение класса типа Java.util.Arrays $ ArrayList для параметра accountIds с ожидаемым типом класса Java.lang.Long из строки запроса ВЫБРАТЬ a.accountManager.loginName FROM Account ГДЕ a.id IN (: accountIds) .
 в Oracle.toplink.essentials.internal.ejb.cmp3.base.EJBQueryImpl.setParameterInternal (EJBQueryImpl.Java:663) 
 в Oracle.toplink.essentials.internal .ejb.cmp3.EJBQueryImpl.setParameter (EJBQueryImpl.Java:202) 
 at com.corenap.newtDAO.ContactDaoBean. 
 at Sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.Java:39) 
 at Sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.Java:25). возвращение на Java Method.Java:597)
at com.Sun.enterprise.security.application.EJBSecurityManager.runMethod (EJBSecurityManager.Java:1011) 
 В com.Sun.ent erprise.security.SecurityUtil.invoke (SecurityUtil.Java:175) 
 at com.Sun.ejb.containers.BaseContainer.invokeTargetBeanMethod (BaseContainer.Java:2920) 
 на com.Sun.ejb.containers.BaseContainer. перехват (BaseContainer.Java:4011) 
 at com.Sun.ejb.containers.EJBObjectInvocationHandler.invoke (EJBObjectInvocationHandler.Java:203) 
... 67 еще 
22
perilandmishap

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

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

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

- Loren

20
perilandmishap

Надеюсь, это кому-нибудь поможет. Я столкнулся с проблемой и сделал следующее, чтобы решить (используя 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 ", т.е. удалил скобки ().

10
dillip

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

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

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

3
Abhishek Chatterjee

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

0
Atul Jain

Да, и если по какой-то причине вы не можете использовать 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;
    }
0
perilandmishap

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