簡體   English   中英

在 JPA Criteria API 中使用 ParameterExpression 與變量

[英]using a ParameterExpression versus a variable in JPA Criteria API

使用 JPA Criteria API 時,直接使用 ParameterExpression 而非變量有什么優勢? 例如,當我希望在 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();
}

使用參數,這將變為:

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();
}

為簡潔起見,我更喜歡第一種方式,尤其是當查詢變得更長並且帶有可選參數時。 使用像 SQL 注入這樣的參數有什么缺點嗎?

你可以像這樣使用 ParameterExpression:假設你有一些輸入過濾器,一個例子可能是這樣的:

  • 在您的查詢中,您必須檢查財務代碼的值。

讓我們開始:首先創建criteriaQuery 和criteriaBuilder 和root

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

1)初始化一個 predicateList(用於 where 子句)和一個 paramList(用於 param)

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

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 ) 創建 where 子句

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

4 ) 設置參數值

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

使用參數時,很可能(取決於 JPA 實現、使用中的數據存儲和 JDBC 驅動程序)SQL 將優化為 JDBC 參數,因此如果您使用不同的參數值執行相同的操作,它將使用相同的 JDBC 語句。

SQL 注入始終取決於開發人員是否驗證用作參數的某些用戶輸入。

在第二種情況下,您不必要地使用了 ParameterExpression。 CriteriaQuery 的 where() 方法接受一個 Predicate 作為它的參數。

取而代之的是:

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();

你可以簡單地使用這個:

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

ParameterExpression 能夠通過其 in()、isNull()、isNotNull() 方法為您生成謂詞,請參閱文檔 在我看來,這將是它的主要優勢。

注意:可以像您一樣使用 ParameterExpression,這相當於將命名參數傳遞給 JPQL 查詢。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM