Mejores prácticas para el uso y persistencia de enums


He visto varias preguntas / discusiones aquí sobre la mejor manera de manejar y persistir valores similares a enum (por ejemplo, Datos persistentes adecuados para enum , Cómo persistir una enumeración usando NHibernate ), y me gustaría preguntar cuál es el consenso general.

En particular:

  • ¿Cómo deben manejarse estos valores en el código?
  • ¿Cómo se deben conservar en una base de datos (como texto/como número)?
  • ¿Cuáles son las compensaciones de diferentes soluciones?

Nota: Moví las explicaciones originalmente incluidas en esta pregunta a una respuesta.

Author: sleske, 2009-04-14

10 answers

Estoy de acuerdo con mucho de lo que dices. Una cosa que me gustaría añadir, sin embargo, sobre la persistencia de enums: No creo que la generación de enums en el tiempo de compilación a partir de los valores de la base de datos sea aceptable, pero también creo que la comprobación de tiempo de ejecución no es una buena solución. Definiría una tercera media: tener una prueba unitaria que compruebe los valores de la enumeración contra la base de datos. Esto evita la divergencia "casual", y evita la sobrecarga de comprobar las enumeraciones contra la base de datos cada vez que el código se ejecuta.

 18
Author: Paul Sonier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-28 20:12:42

El artículo inicial me parece bien. Aún así, basado en los comentarios, parece que algunos comentarios relativos a Java enums podrían aclarar algunas cosas.

Enum type en Java es una clase por definición, pero muchos programadores tienden a olvidar esto, porque lo relacionan con "una lista de valores permitidos" como en otros lenguajes. Es más que eso.

Entonces, para evitar esas instrucciones switch, podría ser razonable poner algún código y métodos adicionales en la clase enum. Hay casi nunca es necesario crear una "clase real tipo enum" separada.

Considere también el punto de la documentación: ¿desea documentar el significado real de su enumeración en la base de datos? ¿En el código fuente que refleja los valores (su tipo de enumeración) o en alguna documentación externa? Personalmente prefiero el código fuente.

Si desea presentar valores de enumeración como enteros en la base de datos debido a la velocidad o por cualquier razón, esa asignación también debe residir en la enumeración de Java. Obtendrás string-name mapeo por defecto, y he estado contento con eso. Hay un número ordinal asociado con cada valor de enumeración, pero usar eso directamente como una asignación entre el código y la base de datos no es muy brillante, porque ese número ordinal cambiará si alguien vuelve a ordenar los valores en el código fuente. O agrega valores de enumeración adicionales entre los valores existentes. O elimina algún valor.

(Por supuesto, si alguien cambia el nombre de la enumeración en el código fuente, la asignación de cadenas predeterminada también se agria, pero es menos probable que ocurra accidentalmente. Y puede protegerse más fácilmente contra eso si es necesario poniendo algunas restricciones de comprobación de tiempo de ejecución y comprobación en la base de datos como ya se sugirió aquí. )

 12
Author: lokori,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-28 15:50:39

En el manejo de código para C# se ha perdido la definición de delcaring el valor 0. Casi sin falta siempre declaro mi primer valor como:

public enum SomeEnum
{
    None = 0,
}

Para servir como un valor nulo. Debido a que el tipo de respaldo es un entero y un entero por defecto es 0, por lo que es masivamente útil en muchos lugares para saber si una enumeración realmente se ha establecido programáticamente o no.

 6
Author: Quibblesome,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-23 15:11:12

Java o C# siempre deben usar enumeraciones en el código. Descargo de responsabilidad: Mi fondo es C#.

Si el valor se desea conservar en una base de datos, los valores integrales de cada miembro de la enumeración deben definirse explícitamente para que un cambio posterior en el código no altere accidentalmente los valores de enumeración traducidos y, por lo tanto, el comportamiento de la aplicación.

Los valores siempre deben conservarse en una base de datos como valores integrales, para proteger contra la refactorización de nombres de enumeración. Mantener la documentación de cada enumeración en un wiki y añadir un comentario al campo de base de datos apuntando a la página wiki que documenta el tipo. También agregue documentación XML al tipo de enumeración que contiene un enlace a la entrada wiki para que esté disponible a través de Intellisense.

Si utiliza una herramienta para generar código CRUD, debería ser capaz de definir un tipo de enumeración para usar en una columna, de modo que los objetos de código generados siempre utilicen miembros enumerados.

Si se necesita aplicar lógica personalizada para un miembro de enumeración, tiene algunos opciones:

  • Si tiene un enum MyEnum, cree una clase estática MyEnumInfo que ofrezca métodos de utilidad para descubrir información adicional sobre el miembro enum, por instrucciones switch o por cualquier medio necesario. Agregar "Info" al final del nombre de la enumeración en el nombre de la clase garantiza que estarán uno al lado del otro en IntelliSense.
  • Decore los miembros de la enumeración con atributos para especificar parámetros adicionales. Por ejemplo, hemos desarrollado un EnumDropDown control que crea un ASP.NET desplegable lleno de valores de enumeración, y un EnumDisplayAttribute especifica el texto de visualización bien formateado para usar para cada miembro.

No he probado esto, pero con SQL Server 2005 o posterior, teóricamente podría registrar código C # con la base de datos que contendría información de enumeraciones y la capacidad de convertir valores en enumeraciones para su uso en vistas u otras construcciones, haciendo un método de traducir los datos de una manera más fácil para utilizar.

 5
Author: David Boike,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-22 17:26:51

he tratado de resumir mi entendimiento. Siéntase libre de editar esto si tiene alguna corrección. Así que aquí va:

En el código

En el código, las enumeraciones deben manejarse usando el tipo de enumeración nativo del lenguaje (al menos en Java y C#), o usando algo como el "patrón de enumeración typesafe". Se desaconseja el uso de constantes simples (Enteros o similares), ya que se pierde la seguridad de tipo (y se hace difícil entender qué valores son entrada legal para p. ej. método).

La elección entre estos dos depende de cuánta funcionalidad adicional se adjunte a la enumeración:

  • Si desea poner un montón de funcionalidad en la enumeración (lo cual es bueno, porque evita cambiar()ing en él todo el tiempo), una clase suele ser más apropiada.
  • Por otro lado, para valores simples similares a enum, la enum del lenguaje es generalmente más clara.

En particular, al menos en Java una enumeración no puede heredar de otra clase, así que si tienes varias enumeraciones con un comportamiento similar que te gustaría poner en una superclase, no puedes usar las enumeraciones de Java.

Enums persistentes

Para persistir las enumeraciones, a cada valor de enumeración se le debe asignar un ID único. Puede ser un entero o una cadena corta. Se prefiere una cadena corta, ya que puede ser mnemotécnica (lo hace más fácil para DBAs, etc.). para entender los datos sin procesar en la base de datos).

  • En el software, cada enumeración debe tener funciones de asignación para convierta entre la enumeración (para su uso dentro del software) y el valor ID (para persistir). Algunos frameworks (por ejemplo (N)Hibernate) tienen un soporte limitado para hacer esto automáticamente. De lo contrario, tienes que ponerlo en el tipo/clase de enumeración.
  • La base de datos debería (idealmente) contener una tabla para cada enumeración que enumere los valores legales. Una columna sería el ID (ver arriba), que es el PK. Las columnas adicionales podrían tener sentido para, por ejemplo, una descripción. Todas las columnas de tabla que contendrán valores de esa enumeración puede usar esta "tabla de enumeración" como un FK. Esto garantiza que los valores de enumeración incorrectos nunca puedan persistir, y permite que la base de datos "se mantenga por sí misma".

Un problema con este enfoque es que la lista de valores legales de enumeración existe en dos lugares (código y base de datos). Esto es difícil de evitar y por lo tanto a menudo se considera aceptable, pero hay dos alternativas:

  • Solo mantenga la lista de valores en la base de datos, genere el tipo de enumeración en el momento de la compilación. Elegante, pero significa que se requiere una conexión de base de datos para que se ejecute una compilación, lo que parece problemático.
  • Defina la lista de valores en el código para ser autoritativos. Comprobar con los valores en la base de datos en tiempo de ejecución (por lo general en el inicio), quejarse/abortar en desajuste.
 4
Author: sleske,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 10:29:49

Almacenar el valor de texto de una enumeración en una base de datos es menos preferido que almacenar un entero, debido al espacio adicional requerido y la búsqueda más lenta. Es valioso porque tiene más significado que un número, sin embargo, la base de datos es para el almacenamiento, y la capa de presentación es para hacer que las cosas se vean bien.

 3
Author: cjk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-14 11:33:59

Bueno, desde mi experiencia, usar enumeraciones para cualquier cosa que no sea para pasar opciones (como banderas) a una llamada inmediata a un método, resulta en switch-ing en algún momento.

  • Si vas a usar la enumeración en todo tu código, entonces podrías terminar con un código que no es tan fácil de mantener (la infame declaración switch)
  • Extender enums es un dolor. Agrega un nuevo elemento de enumeración y termina revisando todo su código para verificar todas las condiciones.
  • Con .NET 3.5, puede agregue métodos de extensión a enumeraciones para que se comporten un poco más como clases. Sin embargo, agregar funcionalidad real de esta manera no es tan fácil ya que todavía no es una clase (terminaría usando switch-es en sus métodos de extensión si no fuera en otro lugar.

Así que para una entidad similar a una enumeración con un poco más de funcionalidad, debe tomarse un tiempo y crearla como una clase, con varias cosas en mente:

  • Para hacer que su clase se comporte como una enumeración, puede forzar a cada clase derivada a instanciar como un Singleton, o anular Igual para permitir la comparación de valores de diferentes instancias.
  • Si su clase es similar a enum, debería significar que no debe contener estado serializable-la deserialización debería ser posible solo desde su tipo (una especie de "ID", como usted dijo).
  • La lógica de persistencia debe limitarse solo a la clase base, de lo contrario extender su "enumeración" sería una pesadilla. En caso de que usted fue para el patrón de Singleton, que tendría que asegurar adecuada deserialización en instancias singleton.
 3
Author: Groo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-27 08:07:40

Cada vez que te encuentres usando "números mágicos" en el cambio de código a enumeraciones. Además del ahorro de tiempo (ya que la magia desaparecerá cuando lleguen los bichos ...) te salvará los ojos y la memoria (los enums significativos hacen que el código sea más legible y se documente automáticamente), ya que adivina qué: probablemente seas la persona que mantenga y desarrolle tu propio código

 3
Author: Yordan Georgiev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-27 19:31:19

En mi humilde opinión, en cuanto a la parte del código:

Debes siempre usar el tipo 'enum' para tus enumeraciones, básicamente obtienes muchos regalos si lo haces: Seguridad de tipo, encapsulación y evitación de conmutadores, el soporte de algunas colecciones como EnumSet y EnumMap y claridad de código.

En cuanto a la parte de persistencia, siempre puede persistir la representación de cadena de la enumeración y cargarla de nuevo usando la enumeración.Método valueOf (String).

 2
Author: MahdeTo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-14 11:27:05

Sé que este es un foro antiguo, ¿y si la base de datos pudiera tener otras cosas integrándose directamente a él? Por ejemplo, cuando la base de datos resultante es el ÚNICO propósito del código. Luego, definirá las enumeraciones en cada integración. Mejor que tenerlos en la base de datos. De lo contrario, estoy de acuerdo con el post original.

 1
Author: Chalky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-05 20:23:49