¿Cuál es la mejor manera de guardar enumeraciones en una base de datos?
Sé Java proporciona name()
y valueOf()
métodos para convertir los valores de enumeración en una cadena y la espalda. Pero, ¿existen otras opciones (flexibles) para almacenar estos valores?
¿Existe una forma inteligente de convertir enumeraciones en números únicos ( ordinal()
no es seguro de usar)?
Actualizar:
¡Gracias por todas las respuestas increíbles y rápidas! Fue como sospechaba.
Sin embargo, una nota al 'kit de herramientas'; 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 mucho código duplicado y, por el momento, Java no admite ninguna solución para esto (una enumeración de Java no puede extender otras clases).
Respuestas:
Ya no almacenamos enumeraciones como valores ordinales numéricos; hace que la depuración y el soporte sean demasiado difíciles. Almacenamos el valor de enumeración real convertido a cadena:
y luego vuelva a leer con:
El problema estaba en el pasado mirando a Enterprise Manager y tratando de descifrar:
versos
este último es mucho más fácil. El primero requería obtener el código fuente y encontrar los valores numéricos que se asignaron a los miembros de la enumeración.
Sí, ocupa más espacio, pero los nombres de los miembros de la enumeración son cortos y los discos duros son baratos, y vale mucho más la pena ayudar cuando tiene un problema.
Además, si usa valores numéricos, está atado a ellos. No puede insertar o reorganizar los miembros sin tener que forzar los valores numéricos antiguos. Por ejemplo, cambiando la enumeración Traje a:
tendría que convertirse en:
para mantener los valores numéricos heredados almacenados en la base de datos.
Cómo ordenarlos en la base de datos
Surge la pregunta: digamos que quería ordenar los valores. Algunas personas pueden querer ordenarlos por el valor ordinal de la enumeración. Por supuesto, ordenar las tarjetas por el valor numérico de la enumeración no tiene sentido:
Ese no es el orden que queremos, los queremos en orden de enumeración:
El mismo trabajo que se requiere si guarda valores enteros es necesario si guarda cadenas:
Pero ese no es el orden que queremos, los queremos en orden de enumeración:
Mi opinión es que este tipo de clasificación pertenece a la interfaz de usuario. Si está ordenando elementos según su valor de enumeración: está haciendo algo mal.
Pero si realmente quisiera hacer eso, crearía una
Suits
tabla de dimensiones:De esta manera, cuando quieras cambiar tus cartas para usar Kissing Kings New Deck Order , puedes cambiarlo con fines de visualización sin tirar todos tus datos:
Ahora estamos separando un detalle de programación interno (nombre de enumeración, valor de enumeración) con una configuración de visualización destinada a los usuarios:
fuente
12.37 ms
a tomar en su lugar12.3702 ms
. Eso es lo que quiero decir con "en el ruido" . Ejecuta la consulta nuevamente y toma13.29 ms
, o11.36 ms
. En otras palabras, la aleatoriedad del programador de subprocesos inundará drásticamente cualquier microoptimización que teóricamente tengas y que no sea visible para nadie de ninguna manera.A menos que tenga razones específicas de rendimiento para evitarlo, le recomendaría usar una tabla separada para la enumeración. Use la integridad de la clave externa a menos que la búsqueda adicional realmente lo mate.
Mesa de trajes:
Mesa de jugadores
suit_id
) son independientes de su valor de enumeración, lo que le ayuda a trabajar con los datos de otros idiomas también.fuente
public enum foo {bar}
comoCREATE TABLE foo (name varchar);
que pueden desincronizarse fácilmente.Yo diría que el único mecanismo seguro aquí es usar el
name()
valor String . Al escribir en la base de datos, puede usar un sproc para insertar el valor y, al leer, usar una vista. De esta manera, si las enumeraciones cambian, hay un nivel de indirección en la vista sproc / para poder presentar los datos como el valor de enumeración sin "imponer" esto en la base de datos.fuente
Como dices, ordinal es un poco arriesgado. Considere, por ejemplo:
Si almacenó esto como ordinales, es posible que tenga filas como:
Pero, ¿qué pasa si actualizas Boolean?
Esto significa que todas sus mentiras serán malinterpretadas como 'archivo no encontrado'
Es mejor usar una representación de cadena
fuente
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 imponer la coherencia de la base de datos declarando una clave externa, aunque en algunos casos puede ser mejor no declararla como una restricción de clave externa, lo que impone un costo en cada transacción. Puede garantizar la coherencia haciendo una verificación periódica, en el momento que elija, con:
La otra mitad de esta solución es escribir un código de prueba que verifique que la enumeración de Java y la tabla de enumeración de la base de datos tengan el mismo contenido. Eso queda como ejercicio para el lector.
fuente
enumID
es de cuatro bytes, por lo que tiene tres bytes adicionales por fila al usar nombres. 3 bytes x 1 millón de filas son 3 MB.enumId
seguramente cabe en dos bytes (las enumeraciones más largas no son posibles en Java) y la mayoría de ellas caben en un solo byte (que algunas bases de datos admiten). El espacio ahorrado es insignificante, pero la comparación más rápida y la longitud fija deberían ayudar.Solo almacenamos el nombre de la enumeración en sí, es más legible.
Nos equivocamos al almacenar valores específicos para enumeraciones donde hay un conjunto limitado de valores, por ejemplo, esta enumeración que tiene un conjunto limitado de estados que usamos un carácter para representar (más significativo que un valor numérico):
y cuando tiene muchos valores, necesita tener un mapa dentro de su enumeración para mantener pequeño ese método getFromXYZ.
fuente
Si guarda enumeraciones como cadenas en la base de datos, puede crear métodos de utilidad para (des) serializar cualquier enumeración:
fuente
Toda mi experiencia me dice que la forma más segura de persistir enums en cualquier lugar es usar un valor de código adicional o id (algún tipo de evolución de la respuesta de @jeebee). Este podría ser un buen ejemplo de idea:
Ahora puede usar cualquier persistencia que haga referencia a sus constantes de enumeración por su código. Incluso si decide cambiar algunos de los nombres de las constantes, siempre puede guardar el valor del código (por ejemplo,
DWARF("dwarf")
aGNOME("dwarf")
)Ok, profundiza un poco más con esta concepción. Aquí hay un método de utilidad que lo ayuda a encontrar cualquier valor de enumeración, pero primero extendamos nuestro enfoque.
Y deje que nuestra enumeración lo implemente:
Este es el momento del método de búsqueda mágica:
Y úsalo como un amuleto:
Race race = resolveByCode(Race.class, "elf")
fuente
Me he enfrentado al mismo problema en el que mi objetivo es conservar el valor de Enum String en la base de datos en lugar del valor ordinal.
Para superar este problema, he utilizado
@Enumerated(EnumType.STRING)
y mi objetivo se resolvió.Por ejemplo, tienes una
Enum
clase:En la clase de entidad, defina
@Enumerated(EnumType.STRING)
:Mientras intenta establecer su valor en Base de datos, el valor de cadena se conservará en la base de datos como "
APPLE
", "ORANGE
" o "LEMON
".fuente
Varios valores con relación OR para uno, campo de enumeración. El concepto para .NET con el almacenamiento de tipos de enumeración en la base de datos como un byte o un int y usando FlagsAttribute en su código.
http://blogs.msdn.com/b/efdesign/archive/2011/06/29/enumeration-support-in-entity-framework.aspx
fuente
Puede usar un valor adicional en la constante de enumeración que puede sobrevivir tanto a los cambios de nombre como al recurso de las enumeraciones:
Para obtener la identificación de la enumeración:
Para obtener la enumeración de una identificación:
Sugiero usar valores sin significado para evitar confusiones si los nombres de la enumeración deben cambiarse.
En el ejemplo anterior, he usado alguna variante de "Numeración básica de filas" dejando espacios para que los números permanezcan probablemente en el mismo orden que las enumeraciones.
Esta versión es más rápida que usar una tabla secundaria, pero hace que el sistema dependa más del código y del conocimiento del código fuente.
Para remediar eso, también puede configurar una tabla con los identificadores de enumeración en la base de datos. O vaya al otro lado y elija los identificadores de las enumeraciones de una tabla a medida que le agrega filas.
Nota al margen : Verifique siempre que no está diseñando algo que deba almacenarse en una tabla de base de datos y mantenerse como un objeto normal. Si puede imaginar que tiene que agregar nuevas constantes a la enumeración en este punto, cuando lo está configurando, es una indicación de que es mejor que cree un objeto regular y una tabla en su lugar.
fuente