0 Replies Latest reply: Nov 28, 2011 3:09 AM by 839824 RSS

    Some suggestions for a generic method for using CriteriaQuery...

    839824
      Hi all,
      I'm try to develop a generic method to recall for all queryies I should do in my JSF web application.
      When I started the project I used the wizard Create JSF pages from Entity Classes on Netbeans and in AbstractFacade it create this method:
          public List<T> findRange(int[] range) {
              javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
              cq.select(cq.from(entityClass));
              javax.persistence.Query q = getEntityManager().createQuery(cq);
              q.setMaxResults(range[1] - range[0]);
              q.setFirstResult(range[0]);
              return q.getResultList();
          }
      the code is simple, the method returns a set of results that start at a number and end to another number. Now I change firstly the method for set an order's criteria and decide dinamically if it retuns a sublist or all results, and this is the code:
              public List<T> findRangeOrdered(int[] range, String order) {
              javax.persistence.criteria.CriteriaQuery<T> cq = (javax.persistence.criteria.CriteriaQuery<T>)getEntityManager().getCriteriaBuilder().createQuery();
              cq.select(cq.from(entityClass));
              javax.persistence.criteria.Root<T> r = cq.from(entityClass);
              if(order!=null){
              if(order.startsWith("desc"))
                      cq.orderBy(getEntityManager().getCriteriaBuilder().desc(r.get(order.substring(order.indexOf("#")+1,order.length()))));
              else
                      cq.orderBy(getEntityManager().getCriteriaBuilder().asc(r.get(order.substring(order.indexOf("#")+1,order.length()))));
              }
                      javax.persistence.Query q = getEntityManager().createQuery(cq);
              if(range!=null){
              q.setMaxResults(range[1] - range[0]);
              q.setFirstResult(range[0]);
              }
              return q.getResultList();
          }
      where order is a string that I wrote like this:
      - "asc#name"
      - or "desc#address"
      ok?
      Now I would add a control for adding some where clauses.
      I though to add a List<String> variable with this format:
      clause<#>field<#>value
      where:
      clause is like: like, equal, in, between ecc;
      field is the name of field to check;
      and value the value to looking for.

      The new method, that I called findFiltered is this:
              public List<T> findFiltered(int[] range, String order, List<String> whereList) {
         List<Predicate> predicateList = new ArrayList<Predicate>();
      String buf;
      int i=0;
              javax.persistence.criteria.CriteriaQuery<T> cq = (javax.persistence.criteria.CriteriaQuery<T>)getEntityManager().getCriteriaBuilder().createQuery();
              cq.select(cq.from(entityClass));
              javax.persistence.criteria.Root<T> r = cq.from(entityClass);
              javax.persistence.criteria.Path<T> path = cq.from(entityClass);
              if(whereList!= null && whereList.size()>0){
      Iterator iter=whereList.iterator();
      Predicate p;
      while (iter.hasNext())
      {
      buf=iter.next().toString();
      
      if(buf.substring(1,buf.length()).startsWith("like"))
        p = getEntityManager().getCriteriaBuilder().like(getEntityManager().getCriteriaBuilder().upper(r.<String>get(buf.substring((buf.indexOf(">")+1),buf.lastIndexOf("<")))), "%"+buf.substring(buf.lastIndexOf(">")+1,buf.length()).toUpperCase()+"%");
      else if(buf.substring(1,buf.length()).startsWith("equal"))
        p = getEntityManager().getCriteriaBuilder().equal(r.get(buf.substring((buf.indexOf(">")+1),buf.lastIndexOf("<"))), buf.substring(buf.lastIndexOf(">")+1,buf.length()));
      else if(buf.substring(1,buf.length()).startsWith("in"))
       p = getEntityManager().getCriteriaBuilder().in(path.get(buf.substring((buf.indexOf(">")+1),buf.lastIndexOf("<"))), buf.substring(buf.lastIndexOf(">")+1,buf.length()).replaceAll("#",","));
      else if(buf.substring(1,buf.length()).startsWith("between"))
       p = getEntityManager().getCriteriaBuilder().between(r.get(buf.substring((buf.indexOf(">")+1),buf.lastIndexOf("<")), buf.substring(buf.lastIndexOf(">")+1,buf..indexOf("##")), buf.substring(buf.lastIndexOf("#")+1,buf.length()));
      else if(buf.substring(1,buf.length()).startsWith("greatest"))
       p = getEntityManager().getCriteriaBuilder().greatest(r.<String>get(buf.substring((buf.indexOf(">")+1,buf.length()));
      else if(buf.substring(1,buf.length()).startsWith("greaterThanOrEqualTo"))
       p = getEntityManager().getCriteriaBuilder().greaterThanOrEqualTo(r.<String>get(buf.substring((buf.indexOf(">"))+1,buf.lastIndexOf("<")))), buf.substring(buf.lastIndexOf(">")+1,buf.length()));
      else if(buf.substring(1,buf.length()).startsWith("lessThanOrEqualTo"))
       p = getEntityManager().getCriteriaBuilder().lessThanOrEqualTo(r.<String>get(buf.substring((buf.indexOf(">"))+1,buf.lastIndexOf("<")))), buf.substring(buf.lastIndexOf(">")+1,buf.length()));
      
      }
              }
       Predicate[] predicates = new Predicate[predicateList.size()];
       PredicateList.toArray(predicates);
       cq.where(predicates);
      
              if(order.startsWith("desc"))
                      cq.orderBy(getEntityManager().getCriteriaBuilder().desc(r.get(order.substring(order.indexOf("#")+1,order.length()))));
              else
                      cq.orderBy(getEntityManager().getCriteriaBuilder().asc(r.get(order.substring(order.indexOf("#")+1,order.length()))));
              }
      
                      javax.persistence.Query q = getEntityManager().createQuery(cq);
              if(range!=null){
              q.setMaxResults(range[1] - range[0]);
              q.setFirstResult(range[0]);
              }
      
              return q.getResultList();
          }
      Now, I have some compiler errors and I don't understand how implement the AND and OR clause in this code, but, however, I would know from you if my work is logical correct or there is a better solution! (it could mean also implement a new framework!)
      For now I'm using JDK1.7, JPA2 and JSF2.
      What do you think about it?
      Thank for your suggestions!

      P.S.: Sorry for my english, I ask to you to don't read all passages really as I wrote but try to understand what I would say :)

      P.S.2: Sorry for the "design" of my code but I'm blind so, sometimes, I don't respect the right structure!

      [EDIT:]
      I'm thinking a thing, I could use an HashMap and not a String for the List's object...
      It could be containes these couple of object:
      - key: "type"; value: the class of the object that I want filtered (for example: String.class, java.util.Date or int);
      - key: "name"; value: the name of the field;
      - key: "value"; value: what i'm looking for;
      and for the clauses that contains mor values (like the between) I should add value2, value3 ecc...
      What do you think about this idea?
      The new problem could be: how I can write the list of else without check before wich is the class of the field?

      Edited by: Filippo Tenaglia on 28-nov-2011 9.56