Carte enum en JPA avec des valeurs fixes?
Je suis à la recherche pour les différentes façons de la carte une énumération en utilisant JPA. Je tiens tout particulièrement à définir la valeur de l'entier de chaque enum d'entrée et de n'enregistrer que la valeur de l'entier.
@Entity
@Table(name = "AUTHORITY_")
public class Authority implements Serializable {
public enum Right {
READ(100), WRITE(200), EDITOR (300);
private int value;
Right(int value) { this.value = value; }
public int getValue() { return value; }
};
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "AUTHORITY_ID")
private Long id;
//the enum to map :
private Right right;
}
Une solution simple est d'utiliser le Énumérées annotation avec EnumType.ORDINAL:
@Column(name = "RIGHT")
@Enumerated(EnumType.ORDINAL)
private Right right;
Mais dans ce cas, JPA cartes enum index (0,1,2) et pas de la valeur que je veux (100,200,300).
Th deux solutions que j'ai trouvées ne semblent pas simple...
Première Solution
Une solution, il est proposé ici, utilise @PrePersist et @test de charge de convertir les enum à un autre domaine et la marque de l'enum champ transitoire:
@Basic
private int intValueForAnEnum;
@PrePersist
void populateDBFields() {
intValueForAnEnum = right.getValue();
}
@PostLoad
void populateTransientFields() {
right = Right.valueOf(intValueForAnEnum);
}
Deuxième Solution
La deuxième solution il est proposé ici proposé un générique de conversion de l'objet, mais encore semble lourd et hibernate-orienté (@Type ne semblent pas exister dans Java EE):
@Type(
type = "org.appfuse.tutorial.commons.hibernate.GenericEnumUserType",
parameters = {
@Parameter(
name = "enumClass",
value = "Authority$Right"),
@Parameter(
name = "identifierMethod",
value = "toInt"),
@Parameter(
name = "valueOfMethod",
value = "fromInt")
}
)
Est-il d'autres solutions ?
J'ai plusieurs idées en tête mais je ne sais pas si elles existent en JPA:
- utiliser le setter et getter méthodes de membre de droite de l'Autorité de la Classe lors d'un chargement et d'enregistrement de l'Autorité de l'objet
- un équivalent idée serait de dire JPA quelles sont les méthodes de Droit enum pour convertir enum pour int et int enum
- Parce que je suis en utilisant le Printemps, est-il possible de dire JPA d'utiliser un convertisseur (RightEditor) ?
- Il est étrange d'utiliser ORDINALE quelqu'un parfois change de place les éléments de l'énumération et de la base de données devient une catastrophe
- ne serait pas le même s'applique à l'utilisation de Nom - que quelqu'un peut changer enum nom(s) et ils sont encore hors de synchronisation avec la base de données...
- Je suis d'accord avec @NatashaKP. N'utilisez pas de ordinale. Pour changer le nom, il n'y a pas une telle chose. Vous êtes en fait la suppression de l'ancienne enum et de l'ajout d'un nouveau avec un nouveau nom, donc, oui, toutes les données stockées serait hors de la synchronisation (sémantique, peut-être 😛 ).
- Oui, il y a 5 solutions que je connais. Voir ma réponse ci-dessous, où j'ai une réponse détaillée.
Vous devez vous connecter pour publier un commentaire.
Pour les versions antérieures à JPA 2.1, JPA ne fournit que deux façons de traiter les énumérations, par leur
name
ou par leurordinal
. Et la norme JPA ne prend pas en charge les types personnalisés. Donc:UserType
, EclipseLinkConverter
, etc). (la deuxième solution). ~ou~int
valeur de ~ou~Je vais illustrer la dernière option (c'est une base de mise en œuvre, l'ajuster si nécessaire):
value
est juste un champ de propriété qui peut être changé. Il n'a même pas à être unique... je pense que la DB de la valeur d'une constante enum doit être traité comme une "interface" de l'enum. C'est une interface à la base de données, que ce enum est destiné à être utilisé. Et depuis l'interface-ness n'est pas explicite et peut provoquer le chaos, je pense que désigné enum propriété doit être utilisée, nomméedbValue
, appliquer votre logique pour quedbValue
plutôt que certains applicatifs valeur.C'est désormais possible avec JPA 2.1:
Plus de détails:
@Converter
, maisenum
doivent être manipulés de manière plus élégante de la boîte!AttributeConverter
MAIS cite code qui n'a rien de la sorte et de ne pas répondre à l'OP.AttributeConverter
@Convert(converter = Converter.class) @Enumerated(EnumType.STRING)
La meilleure approche serait à la carte un ID unique à chaque type enum, évitant ainsi les pièges de l'ORDINAL et de la CORDE. Voir ce post qui décrit les 5 façons vous pouvez mapper un enum.
Prises à partir du lien ci-dessus:
1&2. À L'Aide De @Énumérés
Actuellement, il existe 2 façons de carte enums au sein de votre entités JPA à l'aide de @Énumérés annotation. Malheureusement, les deux EnumType.CHAÎNE et EnumType.ORDINAL ont leurs limites.
Si vous utilisez EnumType.Chaîne puis de renommer l'un de vos types enum sera la cause de votre valeur d'enum à être en décalage avec les valeurs enregistrées dans la base de données. Si vous utilisez EnumType.ORDINAL alors la suppression ou la réorganisation de la des types dans votre enum va provoquer les valeurs enregistrées dans la base de données de la carte de la mauvaise enums types.
Ces deux options sont fragiles. Si l'enum est modifiée sans procéder à une migration de base de données, vous pouvez jeopodise l'intégrité de vos données.
3. Callbacks
Une solution possible serait d'utiliser la JPA du cycle de vie de retour d'appel annotations @PrePersist et @test de charge. C'est assez laid que vous aurez maintenant deux variables dans votre entité. Une cartographie de la valeur stockée dans la base de données, et de l'autre, le réel de l'enum.
4. Cartographie ID unique à chaque type enum
La meilleure solution est de faire un plan de votre enum à une valeur fixe, ou ID, défini dans l'enum. La cartographie de prédéfinies, fixe la valeur de votre code plus robuste. Toute modification de la commande de la enums types, ou le refactoring des noms, ne provoque pas d'effets indésirables.
5. À l'aide de Java EE7 @Convertir
Si vous êtes en utilisant JPA 2.1, vous avez la possibilité d'utiliser le nouveau @Convertir annotation. Cela nécessite la création d'une classe de convertisseur, annotée avec @Convertisseur, à l'intérieur de ce qui vous permettrait de définir quelles sont les valeurs sont enregistrées dans la base de données pour chaque type enum. Au sein de votre entité, vous serait alors d'annoter vos enum avec @Convertir.
Ma préférence: (Numéro 4)
La raison pourquoi je préfère définir mon ID est dans l'énumération que s'opposer à l'utilisation d'un convertisseur, il est bon de l'encapsulation. Seul le type enum doit connaître son ID, et seule l'entité doit savoir au sujet de la façon dont il les cartes de l'enum à la base de données.
Voir l'original post pour l'exemple de code.
De JPA 2.1 vous pouvez utiliser AttributeConverter.
Créer un énumérés classe comme ceci:
Et de créer un convertisseur comme ceci:
Sur l'entité, vous avez juste besoin d':
Vous avez de la chance avec
@Converter(autoApply = true)
peuvent varier selon le conteneur, mais testé à travailler sur Wildfly 8.1.0. Si cela ne fonctionne pas vous pouvez ajouter@Convert(converter = NodeTypeConverter.class)
sur la classe d'entité de la colonne.Le problème est, je pense, que JPA n'a jamais été initié à l'esprit l'idée que nous pourrions avoir un complexe préexistante Schéma déjà en place.
Je pense qu'il y a deux principaux défauts qui en résultent, et spécifiques à Enum:
Aider ma cause et de voter sur JPA_SPEC-47
Ne serait-ce pas plus élégant qu'à l'aide d'un @Convertisseur pour résoudre le problème?
Éventuellement fermer relative au code de Pascal
Je voudrais faire ce qui suit:
Déclarer separetly l'enum, dans son propre fichier:
Déclarer une nouvelle JPA entité nommée Droit
Vous aurez également besoin d'un convertisseur pour la réception de ces valeurs (JPA 2.1 seule et theres un problème de Mauvais pas ici discuter avec ces énumérations d'être directement persisté à l'aide du convertisseur, donc ce sera une route à sens unique seulement)
L'Autorité de l'entité:
En procédant de cette façon, tu ne peux pas régler directement à l'enum champ. Toutefois, vous pouvez définir le champ de Droite au pouvoir, de l'aide
Et si vous avez besoin de comparer, vous pouvez utiliser:
Qui est plutôt cool, je pense. Son pas tout à fait correcte, puisque le convertisseur de ses pas destiné à être utilisé avec des enums. En fait, la documentation dit de ne jamais l'utiliser à cette fin, vous devez utiliser le @Énumérés annotation à la place. Le problème, c'est qu'il y a seulement deux types enum: ORDINALE ou de la CHAÎNE, mais l'ORDINAL est délicate et risqué.
Cependant, si il ne marche pas vous satisfaire, vous pouvez faire quelque chose d'un peu plus hacky et plus simple (ou pas).
Permet de voir.
La RightEnum:
et l'Autorité de l'entité
Dans cette deuxième idée, ce n'est pas une situation parfaite puisque nous pirater l'attribut ordinal, mais son beaucoup moins de codage.
Je pense que la spécification JPA devrait inclure la EnumType.ID où la valeur d'enum champ doit être annoté avec une sorte de @EnumId annotation.