Как использовать список перечислений в качестве параметров в MyBatis Spring Boot?

Как использовать List перечислений в качестве параметра запроса MyBatis? Я уже создал для него обработчик типов и указал сопоставленный тип, как описано в этом другом вопросе. Он возвращает 0 счетчиков, когда он должен быть тысячами.

@Mapper
public interface BadgeMapper {
    @Select("select count(*) from badges where appType in (#{appTypes})")
    int countByType(@Param("appTypes") List<AppType> appTypes);

package com.example.mapper;
@MappedTypes({AppType.class})
public class AppTypeTypeHandler implements TypeHandler<AppType> {

    @Override
    public void setParameter(PreparedStatement ps, int i, AppType parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, parameter.toString()); // use toString not name()
    }

public static enum AppType {
    ANDROID("A", "Android"), THEME("T", "Theme"), ...
    private String val;
    private String desc;
    AppType(String v, String d) { val = v; desc = d; }
    public String toString() {
        return val;
    }
application.properties
mybatis.type-handlers-package=com.example.mapper

В журналах отладки отображаются правильные значения («A», «T», «ST»), но в качестве счетчика печатается 0.

            System.out.println(badgeMapper.countByType(appTypes));
Console
c.s.s.mapper.BadgeMapper.countByType     : ==>  Preparing: select count(*) from badges where appType in (?)
c.s.s.mapper.BadgeMapper.countByType     : ==> Parameters: [A, T, ST](ArrayList)                           
0
MySQL
mysql> select count(*) from badges where appType in ('A', 'T', 'ST');
+----------+
| count(*) |
+----------+
|     2365 |

Справочная документация для MyBatis XML: http://www.mybatis.org/mybatis-3/configuration.html#typeHandlers

Несколько похоже, но для присвоения результатов, а не параметров: stackoverflow.com/a/45781629/148844

Chloe 01.03.2019 00:13

Я пытался where appType in (#{appTypes, typeHandler=com.example.mapper.AppTypeTypeHandler}), но получилось java.lang.ClassCastException: java.util.ArrayList cannot be cast to com.example.model.Badge$AppType.

Chloe 01.03.2019 00:30
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
2
782
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема в том, что обработчик вашего типа вообще не вызывается.

Прежде всего, весь список рассматривается как единое целое и обрабатывается как один аргумент подготовленного оператора JDBC. Это означает, что отдельные элементы не обрабатываются через указанный вами обработчик типа.

Нет переносимого способа установить список в IN параметр подготовленного оператора в JDBC и, следовательно, в mybatis (для этого есть способы, если вы используете postgres).

Если вы используете postgresql, вы можете создать обработчик типов, который будет принимать список перечислений и устанавливать его, используя метод, описанный в вопросе выше.

В общем случае вам необходимо динамически генерировать запрос для обработки каждого значения отдельно:

@Select("<script>select count(*) from enu " +
  " where appType in ( " +
  "<foreach item='appType' collection='appTypes' separator=','>" +
  "   #{appType,typeHandler=AppTypeTypeHandler}" +
  "</foreach>)</script>")
int countByType(@Param("appTypes") List<AppType> appTypes);

В качестве альтернативы вы можете использовать @SelectProvider и построить запрос, используя код Java.

Другие вопросы по теме