简体   繁体   English

在 JPA Criteria API 中使用 ParameterExpression 与变量

[英]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?使用 JPA Criteria API 时,直接使用 ParameterExpression 而非变量有什么优势? Eg when I wish to search for a customer by name in a String variable, I could write something like例如,当我希望在 String 变量中按名称搜索客户时,我可以编写类似

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?使用像 SQL 注入这样的参数有什么缺点吗?

you can use ParameterExpression like this: assume that you have some input filter, an example could be this:你可以像这样使用 ParameterExpression:假设你有一些输入过滤器,一个例子可能是这样的:

  • 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让我们开始:首先创建criteriaQuery 和criteriaBuilder 和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) 1)初始化一个 predicateList(用于 where 子句)和一个 paramList(用于 param)

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

2 )check if the input is null and create predicateList and param 2 ) 检查输入是否为空并创建 predicateList 和 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 3 ) 创建 where 子句

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

4 ) set param value 4 ) 设置参数值

        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.使用参数时,很可能(取决于 JPA 实现、使用中的数据存储和 JDBC 驱动程序)SQL 将优化为 JDBC 参数,因此如果您使用不同的参数值执行相同的操作,它将使用相同的 JDBC 语句。

SQL injection is always down to the developer as to whether they validate some user input that is being used as a parameter. SQL 注入始终取决于开发人员是否验证用作参数的某些用户输入。

In the second case you are using the ParameterExpression unnecessarily.在第二种情况下,您不必要地使用了 ParameterExpression。 The where() method of the CriteriaQuery accepts a Predicate as its argument. CriteriaQuery 的 where() 方法接受一个 Predicate 作为它的参数。

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 . ParameterExpression 能够通过其 in()、isNull()、isNotNull() 方法为您生成谓词,请参阅文档 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.注意:可以像您一样使用 ParameterExpression,这相当于将命名参数传递给 JPQL 查询。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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