web-dev-qa-db-fra.com

Mappage Hibernate @Enumerated

Hibernate fournit une annotation @Enumerated qui prend en charge deux types de mappage Enum en utilisant ORDINAL ou STRING. Lorsque nous mappons en utilisant EnumType.STRING, il prend le "nom" de la variable Enum et non la représentation toString() de la énumération. Ceci est un problème dans les scénarios où la colonne de base de données est composée d'un seul caractère. Par exemple, j'ai l'énumération suivante:

public enum Status{
  OPEN{
   @Override
   public String toString(){
     return "O";}
   },

  WAITLIST{
   @Override
   public String toString(){
     return "W";}
   },

  COMPLETE{
   @Override
   public String toString(){
     return "C";}
   }

}

Lorsque je persiste dans l'énumération Status.OPEN en utilisant @Enumerated(EnumType.STRING), la valeur que Hibernate essaie de stocker dans la base de données est OPEN. Cependant, ma colonne de base de données ne contient qu'un seul caractère et génère donc une exception.

Une façon de résoudre ce problème consiste à modifier le type Enum afin qu'il contienne des caractères uniques (tels que STATUS.O, STATUS.W au lieu de STATUS.OPEN, STATUS.WAITLIST). Cependant, cela réduit la lisibilité. Avez-vous des suggestions pour préserver la lisibilité et mapper Enum sur une colonne à caractère unique?

Merci.

24
saravana_pc
8
Bozho

Le meilleur moyen de personnaliser le mappage pour les enums est d'utiliser AttributeConverter i.e:

@Entity
public class Person {
    ...
    @Basic
    @Convert( converter=GenderConverter.class )
    public Gender gender;
}

public enum Gender {
    MALE( 'M' ),
    FEMALE( 'F' );

    private final char code;

    private Gender(char code) {
        this.code = code;
    }

    public char getCode() {
        return code;
    }

    public static Gender fromCode(char code) {
        if ( code == 'M' || code == 'm' ) {
            return MALE;
        }
        if ( code == 'F' || code == 'f' ) {
            return FEMALE;
        }
        throw ...
    }
}

@Converter
public class GenderConverter
        implements AttributeConverter<Gender, Character> {

    public Character convertToDatabaseColumn(Gender value) {
        if ( value == null ) {
            return null;
        }

        return value.getCode();
    }

    public Gender convertToEntityAttribute(Character value) {
        if ( value == null ) {
            return null;
        }

        return Gender.fromCode( value );
    }
}

Vous pouvez le trouver dans la documentation d'Hibernate: http://docs.jboss.org/hibernate/orm/5.0/mappingGuide/en-US/html_single/#d5e678

13
Ondrej Bozek

Voici un exemple qui utilise des annotations.

http://www.gabiaxel.com/2011/01/better-enum-mapping-with-hibernate.html

Il est toujours basé sur un type d'utilisateur personnalisé. Quatre ans et demi plus tard et je ne connais toujours pas de meilleure façon de le faire.

En règle générale, je conserve mes valeurs enum sous la forme char/int, un ID simple, puis j'utilise une méthode transitoire qui recherche l'énum approprié par la valeur de l'ID simple, par exemple.

@Transient
public MyEnum getMyEnum() {
    return MyEnum.findById(simpleId); // 
}

et...

public enum MyEnum {
    FOO('F'),
    BAR('B');

    private char id;
    private static Map<Character, MyEnum> myEnumById = new HashMap<Character, MyEnum>();

    static {
        for (MyEnum myEnum : values()) {
            myEnumById.put(myEnum.getId(), myEnum);
        }
    }

    private MyEnum(char id) {
        this.id = id;
    }

    public static MyEnum findById(char id) {
        return myEnumById.get(id);
    }

    public char getId() {
        return id;
    }
}