【问题标题】:Java MyBatis Enum string valueJava MyBatis Enum 字符串值
【发布时间】:2017-04-21 20:08:03
【问题描述】:

我觉得这是一个简单的问题,但我尝试过的所有方法都不适合我。我有一个枚举,我有字符串构造函数的原因是因为 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 映射器,它可以合并现有的,并且映射器的参数之一是 TestEnum。到目前为止,这工作得很好,因为枚举值和字符串值是相同的,但我添加了 C("2C")。现在我想使用 mybaits 向表中插入 2C,但它总是插入 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() 没有 getter 错误。我尝试了#{testEnum.display} 和#{testEnum.name} 他们都仍然插入C,而我希望它插入2C。你们知道更简单的处理方法吗?

我不想改变模型对象来传递String而不是TestEnum,因为这个对象在很多地方都被使用了。有没有一种方法可以在不改变模型对象的情况下在mybatis映射器中完成?

感谢您的帮助:)

【问题讨论】:

    标签: java enums mybatis enumeration ibatis


    【解决方案1】:

    您需要的是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));
        }
    }
    

    最后,在你的 mybatis xml 中注册你的 TypeHandler:

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

    【讨论】:

    • 太棒了,正是我需要的。非常感谢
    【解决方案2】:

    如果要插入 Enum 的值,则无需编写任何自定义 TypeHandler

    您需要做的唯一一件事就是在 MyBatis 插入中指定 getter 方法的名称。

    例子:

    SQL:

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

    MyBatis 映射器:

    @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;
        }
    }
    

    在您的情况下,您可以在 SQL 中使用 src = #{testEnum.display}

    【讨论】:

    • MyBatis 是否使用 JSP 表达式语言之类的?
    • 来自mybatis documentation: MyBatis employs powerful OGNL based expressions
    【解决方案3】:

    除了@Malt 答案:

    您尝试的方法不起作用的原因是 MyBatis EnumTypeHandler 默认设置方法的 name() 值并标有 final 因此您无法覆盖它:

    EnumTypeHandler.class(第 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,而不是 BaseTypeHandler(Malt 答案),因为您可以重用某些功能(不是在您的情况下,但可能在其他情况下),以便处理一般的枚举行为。

    【讨论】:

    • 有道理..感谢您的解释
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-02
    • 2017-03-04
    • 1970-01-01
    • 2011-01-18
    • 2014-08-20
    相关资源
    最近更新 更多