缺少SQL枚举类型,不幸的是有些流行的数据库设计模式似乎是创建one table for all enum values(感谢您的链接,Nathan)。多年来我看到了很多这方面的变化,但我目前正在努力解决的问题看起来像这样:
ID | ENUM | VALUE
-----+-------------+----------
1 | DAY_OF_WEEK | SUNDAY
2 | DAY_OF_WEEK | MONDAY
...
7 | DAY_OF_WEEK | SATURDAY
...
18 | PERSON_TYPE | EMPLOYEE
19 | PERSON_TYPE | MANAGER
然后像这样使用 - 例如在人员表中:
ID | NAME | TYPE
----+----------+------
1 | Jane Doe | 19
意思是Jane是一个经理,因为19是人类类型的主键"经理"在枚举表中。
使用JPA(2.1),是否有一种优雅的方法将此构造映射到propper Java枚举?
重要提示:我的"枚举表有很多版本"使用不同的主键值在野外,即" manager"有时可能是#19行,但有时排#231。但是,值在运行时永远不会更改。遗憾的是,更改数据库模式也不是一种选择,但使用任何JPA提供程序的专有功能都是一种选择。
我实际上找到了一个有效的解决方案,但这对我来说太糟糕了:
public enum PersonType { EMPLOYEE, MANAGER }
@Table(name="PERSONS") @Entity public class Persons {
@Id @Column(name="ID") long id;
@Column(name="NAME") String name;
@Convert(converter = PtConv.class) @Column(name="TYPE") PersonType type;
// ...
}
@Converter public class PtConv implements AttributeConverter<PersonType, Integer> {
// In a static initializer run a JDBC query to fill these maps:
private static Map<Integer, PersonType> dbToJava;
private static Map<PersonType, Integer> javaToDb;
@Override public Integer convertToDatabaseColumn(PersonType attribute) {
return javaToDb.get(attribute);
}
@Override public PersonType convertToEntityAttribute(Integer dbData) {
return dbToJava.get(dbData);
}
}
如果CDI在@Converter
中可用,我会和它一起生活 - 但静态构造测试是一场噩梦。
答案 0 :(得分:0)
您可以使用旧式方法:
public final class EnumMapping {
... // define & load singleton data
public int getId(Enum<?> e) {
...
}
public <E extends Enum<E>> E valueOf(int id, Class<E> strictCheck) {
...
return strictCheck.cast(result);
}
}
@Table(name="PERSONS") @Entity public class Persons {
@Id @Column(name="ID") long id;
@Column(name="NAME") String name;
@Column(name="TYPE") int typeId;
public void setPersonType(PersonType type) { this.typeId = EnumMapping.getInstance().getId(type); }
public PersonType getPersonType() { return EnumMapping.getInstance().valueOf(typeId, PersonType.class); }
}
所以你可以(a)使用java枚举来获取/设置值,以及(b)在你想要的特定时刻初始化映射。
答案 1 :(得分:0)
作为参考,这是我解决问题的方法。适当的Java枚举将是我的偏好,我会接受任何比这更好的答案。
@Table(name="PERSONS") @Entity public class Persons {
@Id @Column(name="ID") long id;
@Column(name="NAME") String name;
@Column(name="TYPE") BaseEnum type; // known to be "PersonTypeEnum"
public PersonType getType() {
switch(type.getValue()) {
case "EMPLOYEE": return PersonType.EMPLOYEE;
case "MANAGER": return PersonType.MANAGER;
}
throw new IllegalStateException();
}
public void setType(PersonTypeEnum type) {
this.type = type;
}
// ...
}
@Entity @Inheritance @DiscriminatorColumn(name="ENUM") @Table(name="ENUMS")
public abstract class BaseEnum {
@Id private int id;
@Column(name="VALUE") String value;
// ...
}
@Entity @DiscriminatorValue("PERSON_TYPE")
public class PersonTypeEnum extends BaseEnum { }
因此枚举值的getter和setter有不同的类型,设置值需要引用实体,这进一步扰乱了代码。