将参数设置为 IN 表达式的列表
-
21-09-2019 - |
题
每当我尝试将列表设置为参数以在 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的第三版预览默认或可以插入到2.1。
- 洛伦
希望这对某人有所帮助。我遇到了这个问题并执行了以下操作来解决(使用 eclipselink 2.2.0)
我在类路径中有 JavaEE jar 和 jpa 2 jar(javax.persistence*2*) 。从类路径中删除了 JavaEE。
我正在使用类似的东西
" idItm IN ( :itemIds ) "
抛出异常:
类型类Java.util.ArrayList用于参数itemID,带有预期类型Java.lang.String从查询字符串
解决方案:我刚刚将状态更改为 " idItm IN :itemIds "
, , IE。我去掉了括号()。
简单地说,参数将是列表并将其设置为
"...WHERE a.id IN (:ids)")
.setParameter("ids", yourlist)
这适用于JPA 1.0
哦,如果你不能将EclipseLink出于某种原因,然后这里是你可以用它来所需要的比特添加到您的查询的方法。只需插入生成的字符串到你的查询,你会把“IN A.ID(: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")
<强> IN:IDS 强>代替的 IN(:IDS)强> - 将工作
。试试这个代码,而不是通过@Szymon Tarnowski提供的一个添加或列表..的警告的,如果你有上百个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')
您也可以试试这个语法。
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);