Java MyBatis перечисление строковое значение


Я чувствую, что это простая проблема, но ни одна из вещей, которые я пробовал, не работает для меня. У меня есть перечисление, причина, по которой у меня есть строковый конструктор, заключается в том, что Java не позволяет перечислению быть числовым..Я попробовал AA, AB, 2C напрямую без строкового конструктора, но это дает ошибку. Обратите внимание, что для существующего перечисления я добавляю C("2C").

public enum TestEnum{
      AA("AA"), AB("AB"), C("2C");
      private String display;
    private TestEnum( String display ) {
          this.display = display;
       }
    public String toString() {
          return display;
       }
    public String getDisplay() {
          return display;
       }
    public void setDisplay( String display ) {
          this.display = display;
       }
     public String getName() {
          return display;
       }

Теперь у меня есть MyBatis mapper, который делает слияние, это существует, и один из параметров к mapper - TestEnum. До сих пор это работало нормально, так как перечисление значение и строковое значение одинаковы, но я добавил C("2C"). Теперь я хочу вставить 2C в таблицу, используя mybaits, но он всегда вставляет C.

merge into text t
        using (select #{id} as id from dual) d on (d.id = t.id)
        when matched then
        update set
        appId = #{applId},
        src = #{testEnum}

TestEnum вставляет C, поэтому я изменил его на #{testEnum.toString ()}, который дал мне нет геттера для имени свойства toString () ошибка. Я попробовал #{testEnum.дисплей} и #{testEnum.name} оба они все еще вставляют C, тогда как я хочу, чтобы он вставил 2C. вы, ребята, знаете более простой способ обработки этого?

Я не хочу менять объект модели на передайте строку, а не TestEnum, потому что этот объект используется во многих places.Is есть способ, которым это можно сделать в MyBatis mapper без изменения объекта модели?

Спасибо за помощь :)

3 3

3 ответа:

Что вам нужно, так это TypeHandler

Во-первых, добавьте статический метод к вашему TestEnum, чтобы вернуть TestEnum заданную строку отображения:

public static TestEnum fromDisplay(String display){
    for (TestEnum v : TestEnum.values()){
        if (v.getDisplay().equals(display)){
            return v;
        }
    }
    return null;
}

Затем используйте его для создания вашего TypeHandler:

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

public class TestEnumTypeHandler extends BaseTypeHandler<TestEnum> {

    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, TestEnum parameter, JdbcType jdbcType)
            throws SQLException {
        ps.setString(i, parameter.getDisplay());
    }

    @Override
    public TestEnum getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return TestEnum.fromDisplay(rs.getString(columnName));
    }

    @Override
    public TestEnum getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return TestEnum.fromDisplay(rs.getString(columnIndex));
    }

    @Override
    public TestEnum getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return TestEnum.fromDisplay(cs.getString(columnIndex));
    }
}

Наконец, зарегистрируйте свой TypeHandler в xml-файле mybatis:

<typeHandlers>
  <typeHandler handler="blah.blah.TestEnumTypeHandler "/>
</typeHandlers>

В дополнение к @Malt ответ:

Причина, по которой то, что вы пытаетесь, не работает, это MyBatis EnumTypeHandler по умолчанию устанавливает name() значение метода и помечается final, поэтому вы не можете переопределить его:

EnumTypeHandler.класс (строки 38-44):

  @Override
  public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException {
    if (jdbcType == null) {
      ps.setString(i, parameter.name());
    } else {
      ps.setObject(i, parameter.name(), jdbcType.TYPE_CODE); // see r3589
    }
  }
В противном случае перечисление создается из метода valueOf(type, name), который также использует имя перечисления.
@Override
  public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
    String s = rs.getString(columnIndex);
    return s == null ? null : Enum.valueOf(type, s);
  }

  @Override
  public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
    String s = cs.getString(columnIndex);
    return s == null ? null : Enum.valueOf(type, s);
  }

Таким образом, определенно, вам нужно использовать специальный typeHandler для обработки вашего перечисления, которое имеет специфическое поведение, но я бы extends непосредственно EnumTypeHandler в конкретных обработчиках типа enum, а не BaseTypeHandler (ответ Malt), потому что вы можете повторно использовать некоторые функции (не в вашем случае, но, возможно, в других), поэтому он обрабатывает общее поведение enum.

Вам не нужно писать никаких пользовательских TypeHandler, Если вы хотите вставить значение вашего перечисления.

Единственное, что вам нужно сделать, это указать имя метода getter в вашей вставке MyBatis.

Пример:

SQL:

CREATE TABLE demo
(
    id BIGINT,
    value VARCHAR(10),
    status CHAR(1)
);

MyBatis mapper:

@Update("UPDATE demo SET status = #{status.value} WHERE id= #{uuid}")
    long updateStatus(@Param("status") Status status, @Param("uuid") String uuid);

И перечисление Java:

public enum Status {
    ACTIVE("A"),
    INACTIVE("I");

    Status(final String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }
}

В вашем случае вы можете использовать src = #{testEnum.display} в своем SQL.