Mapeo de enumeraciones con @Enumerated

Tutorial de JPA @EnumeratedUna de las ventajas de utilizar enumeraciones en Java, es podemos limitar los valores posibles para una propiedad, forzando a los desarrolladores a utilizar los valores ya definidos y evitando el margen de error.

@Enumerated

Con JPA también es posible utilizar enumeraciones y pueden ser de mucha ayuda para asegurar que los programadores persistan un valor válido dentro de una lista previamente definida. JPA nos permite mediante la anotación @Enumerated definir la forma en que una enumeración será persistida, las cuales se explican a continuación:

  • String: permite persistir la enumeración por su nombre, lo que significa que será una columna alfanumérica. La anotación quedaría así:
    • @Enumerated(value = EnumType.STRING)
  • Ordinal: esta estrategia persiste un valor entero que corresponde al valor ordinal o posición de valor en la enumeración. La anotación quedaría de la siguiente manera:
    • @Enumerated(value = EnumType.ORDINAL)

Retomaremos la entidad Employee que hemos venido analizando en todo este tutorial y le agregaremos una nueva propiedad que corresponda al status:

package com.obb.jpa.jpaturorial.entity;

import java.util.Calendar;
import java.util.Objects;
import javax.persistence.*;

/**
 * @author Oscar Blancarte
 */
@Entity
@Table(
    name = "EMPLOYEES" , 
    schema = "jpatutorial", 
    indexes = {@Index(name = "name_index", columnList = "name",unique = true)}
)
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY, generator = "EmployeeTable")
    @Column(name = "ID")
    private Long id;
    
    @Column(name = "NAME", nullable = false, length = 150)
    private String name; 
    
    @Column(name = "SALARY", nullable = false, scale = 2)
    private double salary;
    
    @Column(name = "REGIST_DATE", updatable = false, nullable = false)
    @Temporal(TemporalType.DATE)
    private Calendar registDate;
    
    @Column(name="status", nullable = false, length = 8 )
    @Enumerated(value = EnumType.STRING)
    private Status status;
    
    /**
     * GETs and SETs
     */
}

Veamos que la propiedad es de tipo Status, la cual es una enumeración y tiene definida la estrategia String. También podemos ver que está definida la anotación @Column para definir las características de la columna.

Por otra parte, tenemos la enumeración Status la cual tiene los posibles valores ACTIVE e INACTIVE.

package com.obb.jpa.jpaturorial.entity;

/**
 * @author Oscar Blancarte
 */
public enum Status {
    ACTIVE,
    INACTIVE
}

La anotación @Enumerated no es mandataria, pero el hecho de omitirla provocara que JPA determine la estrategia por default, que en nuestro caso sería Ordinal. Por eso yo siempre aconsejo definirla para no tener sorpresas.

Si ejecutamos nuestro el programa para que cree las tablas por nosotros veremos que se creara una columna de tipo VARCHAR ya que definimos String como estrategia. Por otro lado, si utilizamos Ordinal se creará una columna de tipo INT.

Tambíen los quiero invitar a ver mi curso de JPA, donde explico todos estos temas aplicados con API REST, https://codmind.com/courses/jpa

👉👉 Los invito a mi Curso de Mastering JPA, donde habla de todos estos temas y crearemos un API REST para probar todos los conceptos de persistencia.
👈👈

Yo siempre recomiendo utilizar Enumeraciones cuando definamos atributos que requieren valores fijos y previamente determinados, como una lista de valores, pero que esta lista no requiera cambiar en tiempo de ejecución. Una mala opción para utilizarla es para definir listas de valores que en el futuro requieran ampliarse sin necesidad de recompilar.

NOTA: Este artículo es solo una sección del Tutorial de JPA, para ver el contenido completo de este tutorial regresa al Índice en el botón de abajo.

AnteriorÍndiceSiguiente

2 thoughts to “Mapeo de enumeraciones con @Enumerated”

  1. Que pasa si quiere almacenarlo en la BD con un valor que no es el nombre ni el ordinal. Por ejemplo:

    public enum EstadoVerificacion {
    NO_VERIFICADO( 10, “No verificado” ),
    VERIFICADO( 20, “Ya se verifico” ),
    DOCUMENTO_GENERADO( 35, “Documento generado” );

    private final int id;
    private final String description;

    private EstadoVerificacion( int id, String description ) {
    this.id = id;
    this.description = description;
    }

    public int getId() {
    return id;
    }

    public String getDescription() {
    return description;
    }
    }

    Quiero que sea el campo id quien se almacene en la BD.

    Otra pregunta, utilizar el Ordinal ¿no es muy riesgoso? es decir otro programador (en un entorno compartido) puede querer agregar un nuevo estado y no necesariamente meterlo al final, el enum lo permite. Puede que haya un pacto de caballeros de nunca cambiar el orden y agregarlo al final, pero dado que no es una restricción de java, cualquiera puede no conocerla y agregarlo donde mejor le plazca, afectando entonces el número que se venía almacenando en la BD. Yo por eso razón (y quiero saber si hay una mejor práctica) mejor los hago como el ejemplo que pasé y así obligo a que sea ese id y ningún otro, lo malo es que no puedo poner en los entities la enumeración sino tengo que poner un int o long, quitándole elegancia al método, que se viera mucho mejor si se restringe al enum.

    Gracias por su aclaración.

    1. Hola Rober, JPA solo soporta guardar las enumeraciones por el NAME o por el ORDINAL, el ordinal guarda la posición en que se encuentra la enumeración y el NAME guarda el nombre exacto de la enumeración, por lo que que comentas no es posible.
      Con respecto a lo del ordinal, es correcto guardar el ordinal es un riesgo muy grande, incluso yo nunca guardo la enumeración por el ordinal, por lo mismo que mencionas.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *