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

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

у меня есть таблица "статус". Он имеет два столбца: id и name. id-это ПК.

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

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>

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

2 ответов


я работал над этим вопросом с нескольких точек зрения, и вот мои выводы. Предостережение: я сделал все эти исследования, используя 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)

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

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

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

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

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


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

вот как ваш пользовательский обработчик перечисления статуса будет выглядеть

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>

теперь давайте рассмотрим пример, в котором у вас есть следующие две функции Дао,

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, который он использует по умолчанию для обработки перечислений, поэтому не будет необходимости поддерживать правильные имена перечислений в вашей базе данных.