Quelle est la meilleure façon d'enregistrer les énumérations dans une base de données?
Je sais que Java fournit name()
et valueOf()
méthodes pour convertir les valeurs enum dans une chaîne et le dos. Mais existe-t-il d'autres options (flexibles) pour stocker ces valeurs?
Existe-t-il un moyen intelligent de transformer les énumérations en nombres uniques ( ordinal()
n'est pas sûr à utiliser)?
Mettre à jour:
Merci pour toutes les réponses géniales et rapides! C'était comme je le soupçonnais.
Cependant une note à «boîte à outils»; C'est une manière. Le problème est que je devrais ajouter les mêmes méthodes à chaque type Enum que je crée. C'est beaucoup de code dupliqué et, pour le moment, Java ne prend en charge aucune solution pour cela (une énumération Java ne peut pas étendre d'autres classes).
Réponses:
Nous ne stockons plus jamais les énumérations sous forme de valeurs ordinales numériques; cela rend le débogage et le support beaucoup trop difficiles. Nous stockons la valeur d'énumération réelle convertie en chaîne:
puis relisez avec:
Le problème était dans le passé de regarder Enterprise Manager et d'essayer de déchiffrer:
versets
ce dernier est beaucoup plus facile. Le premier nécessitait d'obtenir le code source et de trouver les valeurs numériques affectées aux membres de l'énumération.
Oui, cela prend plus de place, mais les noms des membres de l'énumération sont courts et les disques durs sont bon marché, et cela vaut bien plus la peine d'aider lorsque vous rencontrez un problème.
De plus, si vous utilisez des valeurs numériques, vous y êtes lié. Vous ne pouvez pas insérer ou réorganiser correctement les membres sans avoir à forcer les anciennes valeurs numériques. Par exemple, en modifiant l'énumération Suit en:
devrait devenir:
afin de conserver les valeurs numériques héritées stockées dans la base de données.
Comment les trier dans la base de données
La question se pose: disons que je voulais ordonner les valeurs. Certaines personnes peuvent vouloir les trier par la valeur ordinale de l'énumération. Bien sûr, ordonner les cartes en fonction de la valeur numérique de l'énumération n'a pas de sens:
Ce n'est pas l'ordre que nous voulons - nous les voulons dans l'ordre d'énumération:
Le même travail qui est requis si vous enregistrez des valeurs entières est requis si vous enregistrez des chaînes:
Mais ce n'est pas l'ordre que nous voulons - nous les voulons dans l'ordre d'énumération:
Mon avis est que ce type de classement appartient à l'interface utilisateur. Si vous triez des éléments en fonction de leur valeur d'énumération: vous faites quelque chose de mal.
Mais si vous vouliez vraiment faire cela, je créerais une
Suits
table de dimension:De cette façon, lorsque vous souhaitez modifier vos cartes pour utiliser Kissing Kings New Deck Order, vous pouvez le modifier à des fins d'affichage sans perdre toutes vos données:
Nous séparons maintenant un détail de programmation interne (nom d'énumération, valeur d'énumération) avec un paramètre d'affichage destiné aux utilisateurs:
la source
12.37 ms
à la place12.3702 ms
. C'est ce que j'entends par «dans le bruit» . Vous exécutez à nouveau la requête et cela prend13.29 ms
, ou11.36 ms
. En d'autres termes, le caractère aléatoire du planificateur de threads submergera considérablement toute micro-optimisation que vous avez théoriquement et qui n'est en aucun cas visible par quiconque.À moins que vous n'ayez des raisons de performances spécifiques pour l'éviter, je vous recommande d'utiliser une table distincte pour l'énumération. Utilisez l'intégrité de la clé étrangère à moins que la recherche supplémentaire ne vous tue vraiment.
Table des costumes:
Table des joueurs
suit_id
) sont indépendantes de votre valeur d'énumération, ce qui vous aide également à travailler sur les données d'autres langues.la source
public enum foo {bar}
etCREATE TABLE foo (name varchar);
qui peuvent facilement se désynchroniser.Je dirais que le seul mécanisme sûr ici est d'utiliser la
name()
valeur String . Lors de l'écriture dans la base de données, vous pouvez utiliser un sproc pour insérer la valeur et lors de la lecture, utiliser une vue. De cette manière, si les énumérations changent, il existe un niveau d'indirection dans le sproc / vue pour pouvoir présenter les données en tant que valeur d'énumération sans «imposer» cela au DB.la source
Comme vous le dites, ordinal est un peu risqué. Considérez par exemple:
Si vous avez stocké ceci en tant qu'ordinaux, vous pourriez avoir des lignes comme:
Mais que se passe-t-il si vous avez mis à jour Boolean?
Cela signifie que tous vos mensonges seront mal interprétés comme `` fichier introuvable ''
Mieux vaut simplement utiliser une représentation sous forme de chaîne
la source
Pour une grande base de données, je suis réticent à perdre les avantages de taille et de vitesse de la représentation numérique. Je me retrouve souvent avec une table de base de données représentant le Enum.
Vous pouvez appliquer la cohérence de la base de données en déclarant une clé étrangère - même si dans certains cas, il peut être préférable de ne pas déclarer cela comme une contrainte de clé étrangère, ce qui impose un coût à chaque transaction. Vous pouvez assurer la cohérence en effectuant périodiquement une vérification, aux moments de votre choix, avec:
L'autre moitié de cette solution consiste à écrire du code de test qui vérifie que l'énumération Java et la table d'énumération de la base de données ont le même contenu. Cela reste un exercice pour le lecteur.
la source
enumID
est de quatre octets, vous avez donc trois octets supplémentaires par ligne en utilisant des noms. 3 octets x 1 million de lignes équivaut à 3 Mo.enumId
tient sûrement dans deux octets (des énumérations plus longues ne sont pas possibles en Java) et la plupart d'entre elles tiennent dans un seul octet (que certaines bases de données prennent en charge). L'espace économisé est négligeable, mais la comparaison plus rapide et la longueur fixe devraient aider.Nous stockons simplement le nom enum lui-même - il est plus lisible.
Nous avons joué avec le stockage de valeurs spécifiques pour les énumérations où il y a un ensemble limité de valeurs, par exemple, cette énumération qui a un ensemble limité de statuts que nous utilisons un caractère pour représenter (plus significatif qu'une valeur numérique):
et quand vous avez beaucoup de valeurs, vous devez avoir une carte dans votre énumération pour garder cette méthode getFromXYZ petite.
la source
Si vous enregistrez les énumérations sous forme de chaînes dans la base de données, vous pouvez créer des méthodes utilitaires pour (dé) sérialiser toute énumération:
la source
Toute mon expérience me dit que le moyen le plus sûr de conserver des énumérations n'importe où est d'utiliser une valeur de code ou un identifiant supplémentaire (une sorte d'évolution de la réponse @jeebee). Cela pourrait être un bel exemple d'idée:
Vous pouvez maintenant utiliser n'importe quelle persistance référençant vos constantes d'énumération par son code. Même si vous décidez de changer certains des noms de constantes, vous pouvez toujours enregistrer la valeur du code (par exemple
DWARF("dwarf")
dansGNOME("dwarf")
)Ok, plongez un peu plus profondément avec cette conception. Voici une méthode utilitaire qui vous aide à trouver n'importe quelle valeur d'énumération, mais étendons d'abord notre approche.
Et laissez notre enum l'implémenter:
C'est le moment de la méthode de recherche magique:
Et utilisez-le comme un charme:
Race race = resolveByCode(Race.class, "elf")
la source
J'ai rencontré le même problème où mon objectif est de conserver la valeur Enum String dans la base de données au lieu de la valeur ordinale.
Pour surmonter ce problème, j'ai utilisé
@Enumerated(EnumType.STRING)
et mon objectif a été résolu.Par exemple, vous avez une
Enum
classe:Dans la classe d'entité, définissez
@Enumerated(EnumType.STRING)
:Pendant que vous essayez de définir votre valeur sur Database, la valeur String sera conservée dans Database en tant que "
APPLE
", "ORANGE
" ou "LEMON
".la source
Plusieurs valeurs avec une relation OR pour un champ d'énumération. Le concept pour .NET avec le stockage des types enum dans la base de données comme un octet ou un int et l'utilisation de FlagsAttribute dans votre code.
http://blogs.msdn.com/b/efdesign/archive/2011/06/29/enumeration-support-in-entity-framework.aspx
la source
Vous pouvez utiliser une valeur supplémentaire dans la constante enum qui peut survivre à la fois aux changements de nom et au recours aux énumérations:
Pour obtenir l'identifiant de l'énumération:
Pour obtenir l'énumération à partir d'un identifiant:
Je suggère d'utiliser des valeurs sans signification pour éviter toute confusion si les noms d'énumérations doivent être modifiés.
Dans l'exemple ci-dessus, j'ai utilisé une variante de "Numérotation de ligne de base" en laissant des espaces afin que les nombres restent probablement dans le même ordre que les énumérations.
Cette version est plus rapide que l'utilisation d'une table secondaire, mais elle rend le système plus dépendant du code et de la connaissance du code source.
Pour remédier à cela, vous pouvez également configurer une table avec les identifiants d'énumération dans la base de données. Ou allez dans l'autre sens et choisissez des identifiants pour les énumérations dans une table lorsque vous y ajoutez des lignes.
Note de bas de page : vérifiez toujours que vous ne concevez pas quelque chose qui devrait être stocké dans une table de base de données et conservé comme un objet normal. Si vous pouvez imaginer que vous devez ajouter de nouvelles constantes à l'énumération à ce stade, lorsque vous la configurez, c'est une indication que vous feriez peut-être mieux de créer un objet normal et une table à la place.
la source