29

每当我尝试将列表设置为在 IN 表达式中使用的参数时,都会出现非法参数异常。互联网上的各种帖子似乎表明这是可能的,但它肯定不适合我。我正在使用带有 Toplink 的 Glassfish V2.1。

有没有其他人能够让这个工作,如果是这样怎么办?

这是一些示例代码:

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:您试图从查询字符串 SELECT a.accountManager.loginName FROM Account a WHERE a 中为参数 accountIds 设置类型为 class java.util.Arrays$ArrayList 的值,预期类型为 java.lang.Long .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)
在 com.corenap.newtDAO.ContactDaoBean.getNotificationAddresses(ContactDaoBean.java:437)
在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
在 java.lang.reflect.Method.invoke(Method.java:597)
在 com.sun.enterprise.security.application.EJBSecurityManager.runMethod(EJBSecurityManager.java:1011)
在 com.sun.enterprise.security.SecurityUtil.invoke(SecurityUtil.java:175)
在 com.sun.ejb.containers.BaseContainer.invokeTargetBeanMethod(BaseContainer.java:2920)
在 com.sun.ejb.containers.BaseContainer.intercept(BaseContainer.java:4011)
在 com.sun.ejb.containers.EJBObjectInvocationHandler.invoke(EJBObjectInvocationHandler.java:203)
... 67 更多
4

9 回答 9

49

您的 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();
于 2011-11-01T13:58:28.887 回答
20

我找到了答案,JPA 1.0 不支持提供列表作为参数;但是,它在 JPA 2.0 中受支持。

Glassfish v2.1 的默认持久性提供程序是实现 JPA 1.0 的 Toplink,要获得 JPA 2.0,您需要 EclipseLink,它是 Glassfish v3 预览版的默认值,或者可以插入 v2.1。

- 罗兰

于 2009-10-13T16:48:40.673 回答
13

希望这对某人有所帮助。我遇到了这个问题并做了以下解决(使用eclipselink 2.2.0)

  1. 我在类路径中有 JavaEE jar 和 jpa 2 jar(javax.persistence*2*)。从类路径中删除了 JavaEE。

  2. 我正在使用类似 " idItm IN ( :itemIds ) "抛出异常的东西:

为参数 itemIds 键入 class java.util.ArrayList,并从查询字符串中获取预期的 class java.lang.String 类型

解决方法:我只是把in条件改成了 " idItm IN :itemIds ",即去掉了括号()。

于 2011-07-07T10:30:06.327 回答
3

简单地说,参数将是 List 并将其设置为

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

这适用于 JPA 1.0

于 2013-07-25T06:10:18.927 回答
1

IN :ids而不是 IN (:ids) - 会起作用。

于 2019-01-29T11:02:53.453 回答
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 &gt size; i++) {
            queryString = queryString.concat(" "+field+" = '"+collection.get(i)+"'");
            if(i &gt size-1) {
                queryString = queryString.concat(" OR");
            }
        }
        queryString = queryString.concat(" )");
        return queryString;
    }
于 2010-03-17T20:39:25.900 回答
0

改用 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")
于 2015-03-24T17:18:06.167 回答
-1

尝试使用此代码而不是 @Szymon Tarnowski 提供的代码来添加 OR 列表..警告如果您有数百个 ID,但您可能会打破关于查询最大长度的任何限制。

/**
 * @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' OR myfield = '132' OR myfield = '112')

于 2012-07-25T01:33:51.960 回答
-3

你也可以试试这个语法。

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

于 2011-11-01T13:37:22.167 回答