jpa 在JPQL查询中设置可选参数

2hh7jdfx  于 2023-06-23  发布在  其他
关注(0)|答案(4)|浏览(212)

I got this list of coins that i want to filter with that 3 optional parameters(Currency, quantity and year)
如何将JPQL中的参数设置为可选?我不想做9“如果其他”检查是否为空
我得到了函数filtradoMonedas(filterCoins),它使用3个可选参数过滤对象Moneda(coin),但如果有空参数,它就不工作。
如果不设置空参数,如果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;
}
kgsdhlau

kgsdhlau1#

在阅读了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类中运行得很好。

4dc9hkyq

4dc9hkyq2#

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
myzjeezk

myzjeezk3#

在我的例子中,我的可选参数是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);

这样:

  • 如果参数具有 * 一个或多个值*,则通过 OR 运算符的左侧选择
  • 如果参数categoriesnull,意味着我必须选择 COLUMN_X 的所有值,则 OR 运算符的右侧将始终返回TRUE

为什么是COALESCE,为什么里面有一个 null 值?

让我们探索所有条件下的WHERE子句:

案例一:categories = null

(COLUMN_X IN null OR COALESCE(null, null) IS NULL)
  • OR* 的左边部分将返回false,而 OR 的右边部分将始终返回true,实际上COALESCE将返回第一个非空值(如果存在),并返回null(如果所有参数均为null)。
    案例二:categories = ()
(COLUMN_X IN null OR COALESCE(null, null) IS NULL)

JPA会自动将空列表标识为null值,因此结果与案例1相同。

案例三: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至少需要两个参数。

案例四: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'的行。

hc2pp10m

hc2pp10m4#

这对于原生查询,当参数值需要是可选的时,只需传递空值。检查查询中参数是否为null。

"SELECT m FROM Moneda m WHERE"
+ "(:divisa is null || m.divisa = :divisa) "
+ "AND (:cantidad is null || m.cantidad= :cantidad) "
+ "AND (:ano is null || m.ano = :ano)"

相关问题