This discussion is archived
0 Replies Latest reply: Nov 28, 2011 1:09 AM by 839824 RSS

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

839824 Newbie
Currently Being Moderated
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

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points