代码之家  ›  专栏  ›  技术社区  ›  Chloe

如何使用MyBatis而不是名称将枚举值插入数据库?[副本]

  •  0
  • Chloe  · 技术社区  · 5 年前

    我觉得这是一个简单的问题,但我尝试过的东西都不适合我。我有一个枚举,之所以有字符串构造函数是因为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。你们知道更简单的方法吗?

    我不想将模型对象更改为传递字符串而不是TestEnum,因为这个对象在许多地方都被使用。是否有一种方法可以在mybatis mapper中完成此操作,而无需更改模型对象?

    感谢您的帮助:)

    0 回复  |  直到 7 年前
        1
  •  4
  •   Malt    7 年前

    你需要的是 TypeHandler

    首先,将静态方法添加到 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
  •  4
  •   zappee    7 年前

    您不需要编写任何自定义 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;
        }
    }
    

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

        3
  •  3
  •   Pau    7 年前

    除@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答案),因为您可以重用某些功能(不是在您的情况下,而是在其他情况下),所以它可以处理一般的枚举行为。