Java – HQL checks the size of the list passed in @param

HQL checks the size of the list passed in @param… here is a solution to the problem.

HQL checks the size of the list passed in @param

Is there a way to check util. What size is List? For example, is it empty?

I tried the query below and it generated QuerySyntaxException unmapped with message ???

.. where (:filters IS EMPTY or  (d.id in (:filters))")
    List<EntityXX> getXXX(List<Integer> filters);

Solution

As dbl replied in his comment, it is not possible to check the size of List<> passed as an @Param.

You are using HQL,

so since JPQL queries are always valid HQL queries, I would like to share my solution.

@Query("SELECT p FROM Product p "
            + "LEFT JOIN p.categories category "
            + "WHERE p.name LIKE CONCAT('%', :searchRequest, '%') "
            + "AND p.description LIKE CONCAT('%', :description, '%') "
            + "AND p.price BETWEEN :priceLow AND :priceHigh "
            + "AND p.archived = :archived "
            + "AND category.name IN :selectedCategories "
            + "GROUP BY p "
            + "HAVING SIZE(p.categories) >= :amountOfSelectedCategories"

)
    Page<Product> findAllBySearchModel(
            Pageable pageable,
            @Param("searchRequest") String searchRequest,
            @Param("description") String description,
            @Param("priceLow") BigDecimal priceLow,
            @Param("priceHigh") BigDecimal priceHigh,
            @Param("archived") boolean archived,
            @Param("selectedCategories") List<String> selectedCategories,
            @Param("amountOfSelectedCategories") int amountOfSelectedCategories
    );

Since WHERE… The IN clause always uses an OR condition, and I wanted to narrow my search and I had to find another way to further limit my results.

Therefore, I need the size of the incoming list.
In JPQL, you can easily use SIZE(), except for @Param.

This resulted in a complete workaround to add the size of my list as an extra @Param. I also check for an empty list in my service layer.

if (!searchModel.getSelectedCategories().isEmpty()) {
                return productService.findAllBySearchModel(
                                pageable,
                                searchModel.getSearchRequest(),
                                searchModel.getDescription(),
                                searchModel.getPriceLow(),
                                searchModel.getPriceHigh(),
                                searchModel.isArchivedView(),
                                searchModel.getSelectedCategories(),
                                searchModel.getSelectedCategories().size()
                );
            }

*Note: My code is a bit simplified and not production environment compliant. I just wanted to give a small example for those struggling with the same problem.

Related Problems and Solutions