IN 式のリストとしてパラメータを設定する
-
21-09-2019 - |
質問
IN 式で使用するパラメータとしてリストを設定しようとすると、必ず Illegal argument 例外が発生します。インターネット上のさまざまな投稿では、これが可能であることが示されているようですが、私にとっては確かに機能しません。私は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のためのデフォルトの持続性プロバイダは、Glassfishのv3のプレビュー用のデフォルトであるか、V2.1に差し込むことができるJPA 2.0あなたがのEclipseLinkが必要を取得するには、JPA 1.0を実装しているToplinkのです。
- ローレン
これが誰かの役に立てば幸いです。私はこの問題に直面し、解決するために次のことを行いました(Eclipselink 2.2.0を使用)
クラスパスには JavaEE jar と jpa 2 jar(javax.persistence*2*) がありました。JavaEEをクラスパスから削除しました。
私は次のようなものを使用していました
" idItm IN ( :itemIds ) "
これは例外をスローしていました:
タイプクラスのjava.util.arrayListパラメーターのアイテムインストのquery文字列からの予想タイプのjava.lang.string
解決:状態を次のように変更しました " idItm IN :itemIds "
, 、つまり括弧()を外しました。
単に、パラメータが一覧可能と
として設定します"...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 :ID の代わりに IN (:ids) - 働くでしょう。
ORリストを追加する代わりに@Szymon Tarnowskiから供給される1のこのコードを試してみてください.. の警告のあなたがが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);