JPA Hibernate Persist any Enum (a Map key) in huma

2019-07-26 15:19发布

问题:

Say you have a class which needs to save some mapped items, using any Enum for the key. Using this mapping it generates e.g. varbinary (SQL Server) with a hexadecimal value.

@Entity
public abstract class X {
    @ElementCollection
    private Map<Enum, Boolean> values;
}

This works but the main issue is readability. The data in the database isn't human readable. trying to use @MapKeyEnumerated(EnumType.STRING) or with EnumType.Ordinal doesn't work since the Enum can be any type and that saves the MyEnum.SOME_VALUE as "SOME_VALUE".

Is it possible to intercept the save/retrieve and save a fully qualified name (com.x.myenum.value) or something legible which could be used to restore the enum instead of a hexadecimal value?

回答1:

To store a Map where key is an enum, and get something human readable in db you could try:

@Entity
public class QuestionnaireDefinition{
    ...
    @OneToMany(mappedBy = "questionnaireDefinition", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @MapKeyEnumerated(EnumType.STRING)
    @MapKeyColumn(name = "language", insertable = false, updatable = false)
    private final Map<Language, QuestionnaireDefinitionTranslation> translations = new HashMap<Language, QuestionnaireDefinitionTranslation>();
... }

where QuestionnaireDefinitionTranslation is the entity or value that will be fecthed given the Language enum. In this example the map value is type: QuestionnaireDefinitionTranslation

@Entity
public class QuestionnaireDefinitionTranslation {

    @Enumerated(EnumType.STRING)
    @Column(nullable = false, insertable = true, updatable = true)    
    private Language language;

    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    private QuestionnaireDefinition questionnaireDefinition;

    private String text;
    ...
}

The class Language is an ordinary enum:

public enum Language {
    EN, ES, FI, FR;
}

The idea to make this work is: 1. First persist a the owner class:

QuestionnaireDefinition questionnaireDef = new QuestionnaireDefinition();
em.persist(questionnaireDef );

and then the aggregated class using your enum as key.

QuestionnaireDefinitionTranslation translation = new QuestionnaireDefinitionTranslation();
translation.set(questionnaireDef);
translation.setLanguage(Language.En);
translation.setText("hello");
em.persist(translation);

voilá that's all, you can fetch known by your enum

QuestionnaireDefinition qd = em.find(1,QuestionnaireDefinition.class);
qd.getTranslations().get(Language.EN);

Be aware with transactions, LazyException and that stuff.