Mybatis如何将Integer映射到Enum?

问题描述 投票:0回答:2
java mybatis
2个回答
3
投票

默认的

EnumTypeHandler
映射枚举的名称(例如
"CREATED"
"RUNNING"
),因此列类型必须是
VARCHAR
[1] 等文本类型之一。

由于 MyBatis 对

id
属性一无所知,因此您必须编写自定义类型处理程序。
这是一个示例实现。

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

import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedTypes;
import org.apache.ibatis.type.TypeHandler;

@MappedTypes(Status.class)
public class StatusTypeHandler implements TypeHandler<Status> {
  @Override
  public void setParameter(PreparedStatement ps, 
       int i, Status parameter, JdbcType jdbcType) throws SQLException {
    if (parameter == null) {
      ps.setNull(i, Types.INTEGER);
    } else {
      ps.setInt(i, parameter.getId());
    }
  }

  @Override
  public Status getResult(ResultSet rs, String columnName) throws SQLException {
    return getStatus(rs.getInt(columnName));
  }

  @Override
  public Status getResult(ResultSet rs, int columnIndex) throws SQLException {
    return getStatus(rs.getInt(columnIndex));
  }

  @Override
  public Status getResult(CallableStatement cs, int columnIndex) throws SQLException {
    return getStatus(cs.getInt(columnIndex));
  }

  private static Status getStatus(int id) {
    if (id == 0) {
      return null;
    }
    for (Status status : Status.values()) {
      if (id == status.getId()) {
        return status;
      }
    }
    throw new IllegalArgumentException("Cannot convert " + id + " to Status");
  }
}

您应该全局注册此类型处理程序。
那么大多数情况下就不需要显式指定

typeHandler

  1. 如果您使用mybatis-spring-boot,在配置中指定

    mybatis.type-handlers-package
    可能是全局注册类型处理程序的最简单方法。

  2. 如果您使用 XML 配置,请添加以下内容。

    <typeHandlers>
      <typeHandler
        handler="xxx.yyy.StatusTypeHandler" />
    </typeHandlers>
    

如果

Status
是您项目中唯一的枚举,您可以停止阅读。

但是,如果有许多具有

id
属性的枚举,并且您不想为每个枚举编写类似的自定义类型处理程序,该怎么办?

如果您的枚举实现如下所示的通用接口,您可以编写一个可以映射所有枚举的类型处理程序。

public interface HasId {
  Integer getId();
}

这是一个类型处理程序实现示例。 请注意,它有一个以

java.lang.Class
作为参数的构造函数。

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

import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedTypes;
import org.apache.ibatis.type.TypeHandler;

@MappedTypes(HasId.class)
public class HasIdTypeHandler<E extends Enum<E> & HasId> implements TypeHandler<E> {
  private Class<E> type;
  private final E[] enums;

  public HasIdTypeHandler(Class<E> type) {
    if (type == null)
      throw new IllegalArgumentException("Type argument cannot be null");
    this.type = type;
    this.enums = type.getEnumConstants();
    if (!type.isInterface() && this.enums == null)
      throw new IllegalArgumentException(type.getSimpleName()
          + " does not represent an enum type.");
  }

  @Override
  public void setParameter(PreparedStatement ps, 
      int i, E parameter, JdbcType jdbcType) throws SQLException {
    if (parameter == null) {
      ps.setNull(i, Types.INTEGER);
    } else {
      ps.setInt(i, parameter.getId());
    }
  }

  @Override
  public E getResult(ResultSet rs, String columnName) throws SQLException {
    return getEnum(rs.getInt(columnName));
  }

  @Override
  public E getResult(ResultSet rs, int columnIndex) throws SQLException {
    return getEnum(rs.getInt(columnIndex));
  }

  @Override
  public E getResult(CallableStatement cs, int columnIndex) throws SQLException {
    return getEnum(cs.getInt(columnIndex));
  }

  private E getEnum(int id) {
    if (id == 0) {
      return null;
    }
    for (E e : enums) {
      if (id == e.getId()) {
        return e;
      }
    }
    throw new IllegalArgumentException("Cannot convert " +
      id + " to " + type.getSimpleName());
  }
}

请注意,如果您尝试在映射器中指定此类型处理程序,它可能无法正常工作。有一个已知的问题

[1] 仅供参考,还有另一个用于枚举的内置类型处理程序:

EnumOrdinalTypeHandler
映射枚举的 ordinal


0
投票

这是另一种没有

TypeHandler
的方法。

只需在结果类型类中添加一个setter,其中输入参数应与数据库中的列类型相同。

例如

@Data
public class YourDTO {

    
    private YourEnum yourEnum;

    public void setYourEnum(Integer enumCode) {
        this.yourEnum= YourEnum.fromCode(enumCode);//Call your static method defined in YourEnum
    }

仅此而已。对于mapper.xml 无需再做任何事情。

 <resultMap id="yourDTO" type="YourDTO">
      
        <result property="yourEnum" column="enumCode"/>
© www.soinside.com 2019 - 2024. All rights reserved.