[java] Formas de guardar enumeraciones en la base de datos



4 Answers

A menos que tenga razones específicas de rendimiento para evitarlo, le recomendaría usar una tabla separada para la enumeración. Use integridad de clave externa a menos que la búsqueda extra realmente lo mate.

Tabla de trajes:

suit_id suit_name
1       Clubs
2       Hearts
3       Spades
4       Diamonds

Tabla de jugadores

player_name suit_id
Ian Boyd           4
Shelby Lake        2
  1. Si alguna vez refactoriza su enumeración para que sean clases con comportamiento (como prioridad), su base de datos ya lo modela correctamente
  2. Su DBA está feliz porque su esquema está normalizado (almacenando un solo entero por jugador, en lugar de una cadena completa, que puede tener o no errores tipográficos).
  3. Los valores de su base de datos ( suit_id ) son independientes de su valor de enumeración, lo que le ayuda a trabajar en los datos de otros idiomas también.
Question

¿Cuál es la mejor manera de guardar enumeraciones en una base de datos?

Sé que Java proporciona los métodos name() y valueOf() para convertir los valores enum a String y viceversa. ¿Pero hay otras opciones (flexibles) para almacenar estos valores?

¿Existe alguna manera inteligente de hacer que las enumeraciones sean números únicos ( ordinal() no es seguro de usar)?

Actualizar:

¡Gracias por todas las increíbles y rápidas respuestas! Era como yo sospechaba.

Sin embargo, una nota para 'toolkit'; Esa es una forma. El problema es que tendría que agregar los mismos métodos a cada tipo de Enum que creo. Eso es una gran cantidad de código duplicado y, por el momento, Java no admite ninguna solución para esto (una enumeración Java no puede extender otras clases).




Para una base de datos grande, soy reacio a perder las ventajas de tamaño y velocidad de la representación numérica. A menudo termino con una tabla de base de datos que representa el Enum.

Puede exigir la coherencia de la base de datos declarando una clave externa, aunque en algunos casos podría ser mejor no declararlo como una restricción de clave externa, que impone un costo en cada transacción. Puede garantizar la coherencia al hacer un control periódicamente, en el momento que elija, con:

SELECT reftable.* FROM reftable
  LEFT JOIN enumtable ON reftable.enum_ref_id = enumtable.enum_id
WHERE enumtable.enum_id IS NULL;

La otra mitad de esta solución es escribir algún código de prueba que compruebe que el enum de Java y la tabla enum de la base de datos tienen los mismos contenidos. Eso queda como un ejercicio para el lector.




Toda mi experiencia me dice que la forma más segura de persistir enums en cualquier lugar es usar un valor de código o id adicional (algún tipo de evolución de la respuesta de @jeebee). Este podría ser un buen ejemplo de una idea:

enum Race {
    HUMAN ("human"),
    ELF ("elf"),
    DWARF ("dwarf");

    private final String code;

    private Race(String code) {
        this.code = code;
    }

    public String getCode() {
        return code;
    }
}

Ahora puede ir con cualquier persistencia haciendo referencia a sus constantes enum por su código. Incluso si decide cambiar algunos de los nombres constantes, siempre puede guardar el valor del código (por ejemplo, DWARF("dwarf") a GNOME("dwarf") )

Ok, zambúllete un poco más profundo con esta concepción. Aquí hay algún método de utilidad que le ayuda a encontrar cualquier valor enum, pero primero permite ampliar nuestro enfoque.

interface CodeValue {
    String getCode();
}

Y deje que nuestra enum lo implemente:

enum Race implement CodeValue {...}

Este es el momento para el método de búsqueda mágica:

static <T extends Enum & CodeValue> T resolveByCode(Class<T> enumClass, String code) {
    T[] enumConstants = enumClass.getEnumConstants();
    for (T entry : enumConstants) {
        if (entry.getCode().equals(code)) return entry;
    }
    // In case we failed to find it, return null.
    // I'd recommend you make some log record here to get notified about wrong logic, perhaps.
    return null;
}

Y Race race = resolveByCode(Race.class, "elf") como un amuleto: Race race = resolveByCode(Race.class, "elf")




Me he enfrentado al mismo problema en el que mi objetivo es mantener el valor de Enum String en la base de datos en lugar del valor ordinal.

Para superar este problema, he usado @Enumerated(EnumType.STRING) y mi objetivo se resolvió.

Por ejemplo, tienes una clase Enum :

public enum FurthitMethod {

    Apple,
    Orange,
    Lemon
}

En la clase de entidad, defina @Enumerated(EnumType.STRING) :

@Enumerated(EnumType.STRING)
@Column(name = "Fruits")
public FurthitMethod getFuritMethod() {
    return fruitMethod;
}

public void setFruitMethod(FurthitMethod authenticationMethod) {
    this.fruitMethod= fruitMethod;
}

Mientras intenta establecer su valor en la base de datos, el valor de cadena se conservará en la base de datos como " APPLE ", " ORANGE " o " LEMON ".




Como dices, ordinal es un poco arriesgado. Considera por ejemplo:

public enum Boolean {
    TRUE, FALSE
}

public class BooleanTest {
    @Test
    public void testEnum() {
        assertEquals(0, Boolean.TRUE.ordinal());
        assertEquals(1, Boolean.FALSE.ordinal());
    }
}

Si almacenó esto como ordinales, puede tener filas como:

> SELECT STATEMENT, TRUTH FROM CALL_MY_BLUFF

"Alice is a boy"      1
"Graham is a boy"     0

Pero, ¿qué ocurre si actualizaste Boolean?

public enum Boolean {
    TRUE, FILE_NOT_FOUND, FALSE
}

Esto significa que todas tus mentiras serán malinterpretadas como 'archivo no encontrado'

Mejor usar solo una representación de cadena






Related