سؤال

كلما حاولت تعيين قائمة كمعلمة لاستخدامها في التعبير ، أحصل على استثناء وسيطة غير قانوني. يبدو أن المشاركات المختلفة على الإنترنت تشير إلى أن هذا ممكن ، لكنه بالتأكيد لا يعمل بالنسبة لي. أنا أستخدم 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 V3 أو يمكن توصيله بـ V2.1.

- لورين

أمل أن هذا يساعد شخصاما. لقد واجهت المشكلة وفعلت ما يلي للحل (باستخدام Eclipselink 2.2.0)

  1. كان لدي Javaee Jar وكذلك JPA 2 Jar (Javax.persistence*2*) في مسار الفصل. أزال جافاي من مسار الفصل.

  2. كنت أستخدم شيئًا مثل " idItm IN ( :itemIds ) " الذي كان يرمي الاستثناء:

اكتب class java.util.arraylist for parameter itemids مع نوع متوقع من الفئة java.lang.string من سلسلة الاستعلام

الحل: لقد غيرت للتو الشرط إلى " idItm IN :itemIds ", ، أي أزال الأقواس ().

ببساطة ، ستكون المعلمة قائمة وتعيينها على أنها

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

هذا يعمل لصالح JPA 1.0

أوه ، وإذا لم تتمكن من استخدام Eclipselink لسبب ما ، فإليك طريقة يمكنك استخدامها لإضافة البتات المطلوبة إلى استعلامك. ما عليك سوى إدراج السلسلة الناتجة في استعلامك حيث يمكنك وضع "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;
    }

استخدم اسمه بدلاً من ذلك:

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

في: IDS بدلاً من في (: IDS) - سيعمل.

جرب هذا الرمز بدلاً من الرمز المقدم من Szymon Tarnowski لإضافة أو قائمة .. تحذير إذا كان لديك مئات من الهوية ، فقد تكسر أي حد موجود فيما يتعلق بطول الاستعلام الأقصى.

/**
 * @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));
}

الذي أعطى الإخراج: و (myField = '122' أو myfield = '132' أو 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);

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top