Java MyBatis 枚举字符串值

7

我觉得这是一个简单的问题,但我尝试的所有方法都不能解决。我有一个枚举,我需要使用字符串构造函数是因为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映射器中完成而不改变模型对象吗?

谢谢您的帮助 :)

3个回答

4

如果你要插入枚举类型变量的值,那么你不需要编写任何自定义 TypeHandler

你只需要在 MyBatis 的 insert 中指定 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 表达式语言或其他什么东西吗? - Chloe
从mybatis 文档中得知:MyBatis采用强大的基于OGNL的表达式 - Roman-Stop RU aggression in UA

4
你需要的是一个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>

太棒了,正是我所需要的。非常感谢你。 - Maverick Riz

4
除了 @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);
  }

所以,当你处理具有特定行为的枚举时,肯定需要使用特定的类型处理程序,但我建议在特定的枚举类型处理程序中直接扩展EnumTypeHandler,而不是BaseTypeHandler(Malt答案),因为你可以重新使用一些功能(在你这种情况下可能不需要,但在其他情况下可能需要),从而处理通用的枚举行为。


有道理。谢谢解释。 - Maverick Riz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接