简体   繁体   中英

using a ParameterExpression versus a variable in JPA Criteria API

When using the JPA Criteria API, what is the advantage of using a ParameterExpression over a variable directly? Eg when I wish to search for a customer by name in a String variable, I could write something like

private List<Customer> findCustomer(String name) {
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<Customer> criteriaQuery = cb.createQuery(Customer.class);
    Root<Customer> customer = criteriaQuery.from(Customer.class);
    criteriaQuery.select(customer).where(cb.equal(customer.get("name"), name));
    return em.createQuery(criteriaQuery).getResultList();
}

With parameters this becomes:

private List<Customer> findCustomerWithParam(String name) {
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<Customer> criteriaQuery = cb.createQuery(Customer.class);
    Root<Customer> customer = criteriaQuery.from(Customer.class);
    ParameterExpression<String> nameParameter = cb.parameter(String.class, "name");
    criteriaQuery.select(customer).where(cb.equal(customer.get("name"), nameParameter));
    return em.createQuery(criteriaQuery).setParameter("name", name).getResultList();
}

For conciseness I would prefer the first way, especially when the query gets longer with optional parameters. Are there any disadvantages of using parameters like this, like SQL injection?

you can use ParameterExpression like this: assume that you have some input filter, an example could be this:

  • in your query you have to check the value of a fiscal Code.

let's start: first of all create criteriaQuery and criteriaBuilder and root

        CriteriaBuilder cb = _em.getCriteriaBuilder();
        CriteriaQuery<Tuple> cq = cb.createTupleQuery();
        Root<RootEntity> soggettoRoot = cq.from(RootEntity.class);

1) inizialize a predicateList(use for where clause) and a paramList(use for param)

Map<ParameterExpression,String> paramList = new HashMap();
List<Predicate> predicateList = new ArrayList<>();

2 )check if the input is null and create predicateList and param

if( input.getFilterCF() != null){
            //create ParameterExpression
            ParameterExpression<String> cf = cb.parameter(String.class);


           //if like clause
            predicateList.add(cb.like(root.<String>get("cf"), cf));
            paramList.put(cf , input.getFilterCF() + "%");

           //if equals clause
           //predicateList.add(cb.equal(root.get("cf"), cf));   
           //paramList.put(cf,input.getFilterCF()());
        }

3 ) create the where clause

 cq.where(cb.and(predicateList.toArray(new   Predicate[predicateList.size()])));
TypedQuery<Tuple> q = _em.createQuery(cq);

4 ) set param value

        for(Map.Entry<ParameterExpression,String> entry : paramList.entrySet())
        {
            q.setParameter(entry.getKey(), entry.getValue());
        }

When using a parameter, likely (dependent on JPA implementation, datastore in use, and JDBC driver) the SQL will be optimised to a JDBC parameter so if you execute the same thing with a different value of the parameter it uses the same JDBC statement.

SQL injection is always down to the developer as to whether they validate some user input that is being used as a parameter.

In the second case you are using the ParameterExpression unnecessarily. The where() method of the CriteriaQuery accepts a Predicate as its argument.

Instead of this:

ParameterExpression<String> nameParameter = cb.parameter(String.class, "name");
criteriaQuery.select(customer).where(cb.equal(customer.get("name"), nameParameter));
return em.createQuery(criteriaQuery).setParameter("name", name).getResultList();

You could simply use this:

Predicate predicate = cb.equal(customer.get("name"), name);
criteriaQuery.select(customer).where(predicate);
return em.createQuery(criteriaQuery).getResultList();

ParameterExpression is capable of producing predicates for you through its in(), isNull(), isNotNull() methods, see the documentation . In my opinion this would be its main advantage.

Note: it is possible to use a ParameterExpression like you did, and this is equivalent to passing a named parameter to a JPQL query.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM