将参数设置为IN表达式的列表

时间:2009-10-12 21:37:47

标签: java jpa glassfish jpql toplink-essentials

每当我尝试将列表设置为在IN表达式中使用的参数时,我会得到一个Illegal参数异常。互联网上的各种帖子似乎表明这是可能的,但它肯定不适合我。我正在使用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 个答案:

答案 0 :(得分:37)

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

答案 1 :(得分:20)

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

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

- 洛伦

答案 2 :(得分:10)

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

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

  2. 我使用了" idItm IN ( :itemIds ) "之类的东西,但却抛出异常:

  3.   

    为参数itemIds输入带有预期值的类java.util.ArrayList   查询字符串

    中的类java.lang.String

    解决方案:我刚刚将in状态更改为" idItm IN :itemIds ",即我删除了括号()。

答案 3 :(得分:3)

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

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

这适用于JPA 1.0

答案 4 :(得分: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;
    }

答案 5 :(得分: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")

答案 6 :(得分:0)

IN:ids 代替 IN(:ids)-可以使用。

答案 7 :(得分:-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'或myfield ='132'或myfield ='112')

答案 8 :(得分:-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);