Je cherche les différentes façons de mapper un enum en utilisant JPA. Je veux surtout définir la valeur entière de chaque entrée de l'énumération et ne sauvegarder que la valeur entière.
@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 consiste à utiliser l'annotation Enumerated avec EnumType.ORDINAL :
@Column(name = "RIGHT")
@Enumerated(EnumType.ORDINAL)
private Right right;
Mais dans ce cas, JPA mappe l'index de l'enum (0,1,2) et non la valeur que je veux (100,200,300).
Les deux solutions que j'ai trouvées ne semblent pas simples...
Première solution
Une solution, proposé ici utilise @PrePersist et @PostLoad pour convertir l'enum en un autre champ et marquer le champ enum comme 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 proposé ici propose un objet de conversion générique, mais semble encore lourd et orienté hibernation (@Type ne semble pas exister en 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")
}
)
Existe-t-il d'autres solutions ?
J'ai plusieurs idées en tête mais je ne sais pas si elles existent dans JPA :
- utiliser les méthodes setter et getter du membre droit de la classe Authority lors du chargement et de la sauvegarde de l'objet Authority
- une idée équivalente serait d'indiquer à JPA quelles sont les méthodes de Right enum pour convertir enum en int et int en enum
- Comme j'utilise Spring, y a-t-il un moyen de dire à JPA d'utiliser un convertisseur spécifique (RightEditor) ?
9 votes
Il est étrange d'utiliser ORDINAL car quelqu'un va parfois changer la place des éléments dans l'énumération et la base de données deviendra un désastre.
2 votes
Ne serait-ce pas la même chose pour l'utilisation de Name - quelqu'un peut changer le(s) nom(s) de l'enum et ils sont à nouveau désynchronisés avec la base de données...
2 votes
Je suis d'accord avec @NatashaKP. N'utilisez pas l'ordinal. Pour le changement de nom, il n'y a pas de telle chose. Vous supprimez en fait l'ancienne énumération et en ajoutez une nouvelle avec un nouveau nom, donc oui, toute donnée stockée serait désynchronisée (sémantique, peut-être :P ).
0 votes
Oui, il y a 5 solutions que je connais. Voir ma réponse ci-dessous, où j'ai une réponse détaillée.