2012-04-18 17 views
13

Sé que esto se ha preguntado antes, pero no pude implementar una solución basada en la información que encontré hasta ahora. así que quizás alguien me pueda explicarlo.MyBatis enum usage

Tengo una tabla "estado". Tiene dos columnas: id y nombre. id es un PK.

En lugar de utilizar un estado POJO, me gustaría utilizar una enumeración. He creado una enumeración como sigue:

public enum Status { 
    NEW(1), READY(2), CLOSED(3); 

    private int id; 

    public void setId(int id) { 
     this.id = id; 
    } 

    public int getId() { 
     return this.id; 
    } 

    Status(int id) { 
     this.id = id; 
    } 
} 

aquí es mi asignador

 <select id="getStatusByName" resultType="Status" parameterType="String">  
     SELECT ls.id, ls.name 
     FROM status AS ls 
     WHERE ls.name = #{name} 
    </select> 

pero por alguna razón, cuando intento para recuperar una enumeración, algo se rompe, pero no es una excepción es aventado.

+1

ISTM que setId() en una enumeración es una idea terrible ... :) –

Respuesta

18

He trabajado en esta cuestión desde un par de ángulos y aquí están mis conclusiones. Advertencia: Hice todas estas investigaciones utilizando MyBatis-3.1.1, por lo que las cosas podrían haberse comportado de manera diferente en versiones anteriores.

Primero, MyBatis tiene incorporado EnumTypeHandler. De forma predeterminada, cada vez que especifique una enumeración Java como resultType o parameterType, esto es lo que manejará ese tipo. Para las consultas, al tratar de convertir un registro de la base de datos en una enumeración Java, EnumTypeHandler solo toma un argumento e intenta buscar el valor enum de Java que corresponde a ese valor.

Un ejemplo lo ilustrará mejor. Supongamos que su consulta anterior devuelve 2 y "Ready" cuando paso "Listo" como argumento. En ese caso, recibo el mensaje de error No enum constant com.foo.Status.2. Si invierto el orden de la instrucción SELECT para ser

SELECT ls.name, ls.id 

continuación, el mensaje de error es No enum constant com.foo.Status.Ready. Supongo que puedes deducir lo que está haciendo MyBatis. Tenga en cuenta que EnumTypeHandler está ignorando el segundo valor devuelto por la consulta.

Cambiar su consulta a

SELECT UPPER(ls.name) 

provoca que funcione: se devuelve la enumeración Status.READY.

A continuación, traté de definir mi propio TypeHandler para Status enum. Desafortunadamente, como con el valor predeterminado EnumTypeHandler, solo pude obtener uno de los valores (id o name) para hacer referencia al Enum correcto, no a ambos. Entonces, si la identificación de la base de datos no coincide con el valor que codificó anteriormente, entonces tendrá una discrepancia. Si se asegura de que el ID de la base de datos siempre coincide con el ID que especifica en la enumeración, todo lo que necesita de la base de datos es el nombre (convertido a mayúsculas).

Luego pensé que sería inteligente e implementaría MyBatis ObjectFactory, tomaría el ID int y el nombre de la cadena y me aseguraría de que coincidan en la enumeración Java que devuelvo, pero eso no funcionó ya que MyBatis no llama ObjectFactory para un tipo de enumeración Java (al menos no pude hacer que funcione).

Así que mi conclusión es que las enumeraciones de Java en MyBatis son sencillas siempre que solo tenga que hacer coincidir el nombre de la base de datos con el nombre de la constante enum; utilice el EnumTypeHandler integrado o defina el suyo propio haciendo UPPER (nombre) en el SQL no es suficiente para que coincida con los nombres enum de Java. En muchos casos, esto es suficiente, ya que el valor enumerado puede ser simplemente una restricción de verificación en una columna y solo tiene el valor único, no una identificación también.Si también necesita hacer coincidir un ID int y un nombre, haga que los ID coincidan de forma manual al configurar el enum de Java y/o las entradas de la base de datos.

Finalmente, si desea ver un ejemplo de esto, vea koan 23 de mis koans MyBatis aquí: https://github.com/midpeter444/mybatis-koans. Si solo quiere ver mi solución, busque en el directorio completado-koans/koan23. También tengo un ejemplo de insertar un registro en la base de datos a través de una enumeración de Java.

6

Puede usar Custom TypeHandler para convertir su resultado directamente en ENUM para que no tenga que poner todos los valores en su base de datos como UPPER CASE ENUM Names.

Esta es la forma en que su estado de enumeración personalizada Handler se verá como

public class StatusTypeHandler implements TypeHandler<Status> { 

public Status getResult(ResultSet rs, String param) throws SQLException { 
    return Status.getEnum(rs.getInt(param)); 
} 

public Status getResult(CallableStatement cs, int col) throws SQLException { 
    return Status.getEnum(cs.getInt(col)); 
} 

public void setParameter(PreparedStatement ps, int paramInt, Status paramType, JdbcType jdbctype) 
     throws SQLException { 
    ps.setInt(paramInt, paramType.getId()); 
} 
} 

Define tu TypeHandler para manejar estado por defecto en su SqlMapConfig.xml añadiendo este código.

<typeHandlers> 
      <typeHandler javaType='Status' handler='StatusTypeHandler' /> 
    </typeHandlers> 

Consideremos ahora un ejemplo en el que haya dos funciones siguientes en su Dao,

Status getStatusById(int code); 
Status getStatusByName(String name); 

Su asignador se verá como

<select id="getStatusById" resultType="Status" parameterType="int">  
    SELECT ls.id 
    FROM status AS ls 
    WHERE ls.id = #{id} 
</select> 

<select id="getStatusByName" resultType="Status" parameterType="String">  
    SELECT ls.id 
    FROM status AS ls 
    WHERE ls.name = #{name} 
</select> 

Ahora bien, como la resultType tanto para el mapeador es Status, myBatis usará CustomTypeHandler para este tipo, es decir, StatusTypeHandler en lugar de EnumTypeHandler que usa de manera predeterminada para el manejo de los registros, por lo que no habría necesidad de mantener Enum adecuado. nombres en su base de datos.

+0

¿Qué sucede si necesito devolver la enumeración sin pasar argumentos (identificación, nombre, etc.)? – axcdnt

+2

Esa es la respuesta que proporciona una solución limpia. Confiar en mayúsculas es feo. – Eduardo