Подтвердить что ты не робот

Использование перечисления MyBatis

Я знаю, что это было задано раньше, но я не смог реализовать решение на основе информации, которую я нашел до сих пор. так что, возможно, кто-то может объяснить это мне.

У меня есть таблица "status". Он имеет два столбца: id и имя. id - это PK.

Вместо использования POJO Status я хотел бы использовать перечисление. Я создал такое перечисление следующим образом:

public enum Status {
    NEW(1), READY(2), CLOSED(3);

    private int id;

    public void setId(int id) {
        this.id = id;
    }

    public int getId() {
        return this.id;
    }

    Status(int id) {
        this.id = id;
    }
}

вот мой картограф   

     <select id="getStatusByName" resultType="Status" parameterType="String">       
        SELECT  ls.id, ls.name
        FROM status AS ls
        WHERE ls.name = #{name}
    </select>

но по какой-то причине, когда я пытаюсь получить перечисление, что-то ломается, но исключение не генерируется.

4b9b3361

Ответ 1

Я работал над этим вопросом с нескольких углов, и вот мои выводы. Предостережение. Я провел все эти исследования с использованием MyBatis-3.1.1, поэтому в ранних версиях в противном случае все могло бы быть по-другому.

Во-первых, MyBatis имеет встроенный EnumTypeHandler. По умолчанию, когда вы укажете переименование Java как resultType или parameterType, это то, что будет обрабатывать этот тип. Для запросов при попытке преобразовать запись базы данных в перечисление Java, EnumTypeHandler принимает только один аргумент и пытается найти значение перечисления Java, соответствующее этому значению.

Пример лучше иллюстрирует. Предположим, что ваш запрос выше возвращает 2 и "Ready", когда я передаю "Готов" в качестве аргумента. В этом случае я получаю сообщение об ошибке No enum constant com.foo.Status.2. Если я отменил порядок инструкции SELECT как

SELECT ls.name, ls.id

тогда сообщение об ошибке No enum constant com.foo.Status.Ready. Я предполагаю, что вы можете сделать вывод о том, что делает MyBatis. Обратите внимание, что EnumTypeHandler игнорирует второе значение, возвращаемое из запроса.

Изменение вашего запроса на

SELECT UPPER(ls.name)

заставляет его работать: возвращается перечисление Status.READY.

Итак, я попытался определить свой собственный TypeHandler для перечисления состояния. К сожалению, как и по умолчанию EnumTypeHandler, я мог получить только одно из значений (id или name), чтобы ссылаться на правое Enum, а не на оба. Поэтому, если идентификатор базы данных не соответствует указанному выше значению, то у вас будет несоответствие. Если вы убедитесь, что идентификатор базы данных всегда совпадает с идентификатором, указанным в перечислении, то все, что вам нужно от базы данных, это имя (преобразованное в верхний регистр).

Затем я подумал, что я умный и реализую объект MyBatis ObjectFactory, захвачу как имя int, так и имя String и гарантирую, что они совпадают с перечислением Java, которое я передал, но это не работает, поскольку MyBatis не вызывает ObjectFactory для типа перечисления Java (по крайней мере, я не мог заставить его работать).

Итак, мой вывод состоит в том, что перечисления Java в MyBatis просты, поскольку вам просто нужно совместить имя из базы данных с именем константы enum - либо использовать встроенный EnumTypeHandler, либо определить свой собственный, если делать UPPER (name ) в SQL недостаточно, чтобы соответствовать именам переименования Java. Во многих случаях этого достаточно, так как перечислимое значение может быть просто контрольным ограничением для столбца, и оно имеет только одно значение, а не идентификатор. Если вам нужно также совместить идентификатор int, а также имя, то при настройке записей перечисления Java и/или базы данных вручную следует сопоставить идентификаторы.

Наконец, если вы хотите увидеть рабочий пример этого, см. koan 23 моих MyBatis koans здесь: https://github.com/midpeter444/mybatis-koans. Если вы просто хотите увидеть мое решение, загляните в каталог complete-koans/koan23. У меня также есть пример вставки записи в базу данных через перечисление Java.

Ответ 2

Вы можете использовать Custom TypeHandler для преобразования результата непосредственно в ENUM, так что вам не нужно помещать все значения в вашу базу данных в качестве имен UPPER CASE ENUM.

Таким образом пользовательский обработчик Status Enum будет выглядеть как

public class StatusTypeHandler implements TypeHandler<Status> {

public Status getResult(ResultSet rs, String param) throws SQLException {
    return Status.getEnum(rs.getInt(param));
}

public Status getResult(CallableStatement cs, int col) throws SQLException {
    return Status.getEnum(cs.getInt(col));
}

public void setParameter(PreparedStatement ps, int paramInt, Status paramType, JdbcType jdbctype)
        throws SQLException {
    ps.setInt(paramInt, paramType.getId());
}
}

Определите свой TypeHandler для обработки состояния по умолчанию в mybatis-config.xml, добавив этот код.

    <typeHandlers> 
            <typeHandler javaType='Status' handler='StatusTypeHandler' /> 
    </typeHandlers>

Теперь рассмотрим пример, в котором у вас есть две функции в вашем Dao,

Status getStatusById(int code);
Status getStatusByName(String name);

Ваш картограф будет выглядеть как

<select id="getStatusById" resultType="Status" parameterType="int">       
    SELECT  ls.id
    FROM status AS ls
    WHERE ls.id = #{id}
</select>

<select id="getStatusByName" resultType="Status" parameterType="String">       
    SELECT  ls.id
    FROM status AS ls
    WHERE ls.name = #{name}
</select>

Теперь как resultType для обоих параметров отображения является Status, myBatis будет использовать CustomTypeHandler для этого типа, то есть StatusTypeHandler вместо EnumTypeHandler, который он использует по умолчанию для Handy Enums, поэтому нет необходимости поддерживать правильные имена Enum в вашей базе данных.