Помогите написать hql запрос

Рейтинг: 2Ответов: 1Опубликовано: 12.06.2023

Есть запрос в бд, который джойнит 3 таблички и достает кастомеров, так же есть 4 необязательных параметра на вход для фильтрации, все параметры отрабатывают нормально, кроме List<UUID> projects (фильтрует кастомеров по проектам из этого листа).

Если не передавать его, то, как и должно, возвращаются все, а если передать, то падает с ошибкой

class java.util.ArrayList cannot be cast to class java.util.UUID (java.util.ArrayList and java.util.UUID are in module java.base of loader 'bootstrap')

Сама проблема во второй части условия:

(rca.projectId IN (:projects) OR (:projects) IS NULL)

Если не делать условие is null, то все ок.

Ещё особенность в том, что через консоль запрос работает хорошо в таком виде, а в коде уже нет.

Перегружать метод с этим параметром и без него не красивый вариант, хоть и рабочий, хочется сделать всё в одном

@Query(value = """
        SELECT NEW com.dhabits.code.analysis.codeache.user.db.model.CustomerFullInfo(c.id, c.username, c.email, c.firstName, c.lastName, c.middleName,
        c.company, c.accountNonExpired, c.accountNonLocked, c.credentialsNonExpired, c.enabled, c.createdAt, rca.projectId, rca.roleId, cast(rl.role as string) )
        FROM Customer AS c
        JOIN RoleCustomerAssignment rca
        ON c.id = rca.customerId
        JOIN Role rl
        ON rca.roleId = rl.id
        WHERE (rca.projectId IN (:projects) OR (:projects) IS NULL)
        AND (cast(rl.role AS string) = :role OR :role IS NULL)
        AND (c.username = :name OR :name IS NULL)
        AND (c.enabled = :enabled OR :enabled IS NULL)
                                          """)
Page<CustomerFullInfo> findAllCustomersFullInfo(@Param("role") String role, @Param("projects") List<UUID> projects, @Param("name") String name, @Param("enabled") Boolean enabled, Pageable pageable);

Пробовал кастить cast((:projects) as char ) - не помогает, переставлял условия местами, играл со скобками - ничего не помогает.

Ответы

▲ 2Принят

Вам нужно изменить код, вызывающий репозиторный метод, таким образом, чтобы вместо null передавать пустой список, а запрос переписать вот так:

@Query(value = """
        SELECT NEW com.dhabits.code.analysis.codeache.user.db.model.CustomerFullInfo(c.id, c.username, c.email, c.firstName, c.lastName, c.middleName,
        c.company, c.accountNonExpired, c.accountNonLocked, c.credentialsNonExpired, c.enabled, c.createdAt, rca.projectId, rca.roleId, cast(rl.role as string) )
        FROM Customer AS c
        JOIN RoleCustomerAssignment rca
        ON c.id = rca.customerId
        JOIN Role rl
        ON rca.roleId = rl.id
        WHERE ((:#{#projects.isEmpty()} = false) AND rca.projectId IN (:projects))
        AND (cast(rl.role AS string) = :role OR :role IS NULL)
        AND (c.username = :name OR :name IS NULL)
        AND (c.enabled = :enabled OR :enabled IS NULL)
                                          """)
Page<CustomerFullInfo> findAllCustomersFullInfo(@Param("role") String role, @Param("projects") List<UUID> projects, @Param("name") String name, @Param("enabled") Boolean enabled, Pageable pageable);

Таким образом, для пустого списка projects выше условие схлопнется в истину и вы не будете выполнять поиск по ключам проектов. См. мой ответ тут: https://stackoverflow.com/questions/76226436/spring-data-jpa-spel-dynamically-adds-where-jpql-clause/76230472#76230472