MyBatis установка аргументов в SelectProvider
Недавно перешли на MyBatis, столкнулись с проблемой подстановки аргументов в SelectProvider.
@SelectProvider( type = OrganisationSelectProvider.class, method = "search")
List<Organization> search(@Param("filter") OrganizationFilter organizationFilter, @Param("sort") SortState sort);
public String search(
OrganizationFilter filter,
SortState sort ) {
return new SQL() {{
SELECT( "*" );
FROM( "organization" );
if( filter.getSearch() != null && !filter.getSearch().isBlank() ) {
WHERE( "inn like '%' || #{filter.search} || '%'" );
OR();
WHERE( "ogrn like '%' || #{filter.search} || '%'" );
OR();
WHERE( "name like '%' || #{filter.search} || '%'" );
}
ORDER_BY( "#{sort.field} #{sort.direction.name}" );
LIMIT( filter.getLimit() );
OFFSET( filter.getOffset() );
}}.toString();
}
При таком обращении к полям аргументов происходит исключение
org.springframework.jdbc.BadSqlGrammarException:
Error querying database. Cause: org.postgresql.util.PSQLException: ERROR: syntax error at or near "$5"
А сам сформированный запрос выглядит следующим образом
SELECT * FROM organization
WHERE (inn like '%' || #{filter.search} || '%')
OR (ogrn like '%' || #{filter.search} || '%')
OR (name like '%' || #{filter.search} || '%')
ORDER BY #{sort.field} #{sort.direction.name} LIMIT 10 OFFSET 0
Собственно возник вопрос, умеет ли SelectProvider таким образом обращаться к полям объектов, переданным в метод? Если да, то какой должен быть синтаксис?
Ответы (1 шт):
Тут проблема не в SelectProvider, а в использовании связываемых переменных (bounded variables).
Программный интерфейс доступа к БД позволяет использовать запросы с параметрами. В них отдельно передается запрос с обозначенными местами подстановки параметров и отдельно сами значения параметров.
Только дело в том, что эти параметры допускаются не во всех местах в запросе. Например, нельзя с использованием связываемой переменной задать имя таблицы или имя ключевое слово (ASC/DESC), которое задает порядок сортировки.
В mybatis синтаксис для связываемых переменных - #{expression}. В этом месте запроса будет использован связываемый параметр, а его значение возьмется из expression.
Для того, чтоб задавать динамически части запроса, в которых нельзя использовать параметры нужно использовать подстановку строк. В этом случае в сам запрос будет вставленно значение выражение как строка. Для этого в mybatis нужно использовать синтаксис ${expression}.
У вас проблема возникает потому, что имя колонки, по которой происходит сортировка и направление сортировки нельзя задавать связываемым параметром.
Итого в вашем случае нужно заменить #{sort.field} #{sort.direction.name} на ${sort.field} ${sort.direction.name}