![](/img/trans.png)
[英]JPQL query for select on entities having @OneToMany relation with optional search parameters
[英]Set optional parameters in JPQL Query
我得到了我想用 3 個可選參數(貨幣、數量和年份)過濾的硬幣列表
如何將 JPQL 中的參數設置為可選? 我不想做 9 個“if else”來檢查它是否為空
我得到了使用 3 個可選參數過濾對象 Moneda(coin) 的函數 filtradoMonedas (filterCoins),但如果有一個空參數,它就不起作用。
如果不設置空參數,如果 cantidad 或 ano 是 "" 返回錯誤查詢的異常,這只會很好地工作。 只是想把它作為一個可選的。 方法如下:
public List<Moneda> filtradoMonedas(Divisa divisa, BigDecimal cantidad,
BigDecimal ano){
EntityManager em = getEntityManager();
Query consulta = em.createQuery("SELECT m FROM Moneda m "
+ "WHERE m.divisa = :divisa "
+ "AND m.cantidad= :cantidad "
+ "AND m.ano = :ano");
consulta.setParameter("divisa", divisa);
consulta.setParameter("cantidad", cantidad);
consulta.setParameter("ano", ano);
List<Moneda> filtradoMonedas = (List<Moneda>) consulta.getResultList();
// sincronizar los objetos devueltos con la base de datos
for (Moneda m : filtradoMonedas) {
em.refresh(m);
}
em.close();
return filtradoMonedas;
}
在閱讀了 Ilya Dyoshin 的評論以及“您應該認為不是參數是可選的,而是條件是可選的”背后的聰明想法后,我決定通過使用帶有 @Query 注釋的 JPQL 走自己的路,並創建一個運行良好的動態 SQL 查詢.
關鍵是應用一些 SQL 邏輯來使條件成為可選的而不是參數:
@Query("SELECT a " +
"FROM amazing " +
"WHERE (:filterSuperAwesome IS NULL " +
"OR a.filterSuperAwesome = :filterSuperAwesome)");
List<FilterSuperAwesome> filterAwesomeORSuperAwesome(
@Param("filterSuperAwesome ") FilterSuperAwesome filterSuperAwesome);
注意這里☝️,我使用 OR 語句是基於我的參數可以呈現兩種形式,FilterSuperAwesome 或 NULL 的實例。 當為 NULL 時,條件始終為 True,就好像它不存在一樣。
這在 JHipster 項目的 JpaRepository 類中工作得很好。
JPQL 不支持可選參數。
實際上,您應該認為不是參數是可選的,而是條件是可選的。 這個想法將引導您創建“動態”查詢。 這將引導您下一步從 JPQL 切換到 Criteria API。 這將導致你寫出這樣的東西:
// Actually can be generated during build, and thus can be ommited
@StaticMetamodel(Moneda.class)
abstract class Moneda_ {
public static volatile SingularAttribute<Moneda, BigDecimal> cantidad;
public static volatile SingularAttribute<Moneda, Divisia> divisia;
public static volatile SingularAttribute<Moneda, BigDecimal> ano;
}
final CriteriaBuilder cb = em.getCriteriaBuilder();
final CriteriaQuery<Moneda> cq = cb.createQuery(Moneda.class);
final Root<Moneda> root = cq.from(Moneda.class);
Set<Predicate> predicates = new HashSet<>(3);
if (cantidad != null) {
predicates.add(cb.equal(root.get(Moneda_.cantidad), cantidad));
}
if (ano != null) {
predicates.add(cb.equal(root.get(Moneda_.ano), ano));
}
if (divisia != null) {
predicates.add(cb.equal(root.get(Moneda_.divisia), divisia));
}
cq.where(predicates.toArray(new Predicate[predicates.size()]));
em.createQuery(cq).getResultList();
// and do whatever you want
就我而言,我遇到的問題是我的可選參數是List<String>
,解決方案如下:
@Query(value = "SELECT *
FROM ...
WHERE (COLUMN_X IN :categories OR COALESCE(:categories, null) IS NULL)"
, nativeQuery = true)
List<Archive> findByCustomCriteria1(@Param("categories") List<String> categories);
這邊走:
COALESCE
以及為什么它里面有一個空值?WHERE
子句: 案例 1: categories = null
(COLUMN_X IN null OR COALESCE(null, null) IS NULL)
的左側或將返回false,而右面部分或將始終返回true,其實COALESCE
將返回第一個非空值(如果存在)並返回null如果所有參數都為空。
案例 2: categories = ()
(COLUMN_X IN null OR COALESCE(null, null) IS NULL)
JPA 會自動將空列表識別為空值,因此結果與案例 1 相同。
案例 3: categories = ('ONE_VALUE')
(COLUMN_X IN ('ONE_VALUE') OR COALESCE('ONE_VALUE', null) IS NULL)
OR的左側部分將僅針對COLUMN_X = 'ONE_VALUE'
那些值返回 true,而OR的右側部分將永遠不會返回 true,因為它等於'ONE_VALUE' IS NULL
(即 false)。
為什么 null 作為第二個參數? 嗯,那是因為COALESCE
至少需要兩個參數。
案例 4: categories = ('ONE_VALUE', 'TWO_VALUE')
(COLUMN_X IN ('ONE_VALUE', 'TWO_VALUE') OR COALESCE('ONE_VALUE', 'TWO_VALUE', null) IS NULL)
與案例 3 一樣, OR運算符的左側部分將僅選擇COLUMN_X
等於'ONE_VALUE'
或'TWO_VALUE'
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.