Java 使用固定值映射JPA中的枚举?
我正在寻找使用JPA映射枚举的不同方法。我特别想设置每个枚举项的整数值,并且只保存整数值Java 使用固定值映射JPA中的枚举?,java,spring,orm,jpa,enums,Java,Spring,Orm,Jpa,Enums,我正在寻找使用JPA映射枚举的不同方法。我特别想设置每个枚举项的整数值,并且只保存整数值 @Entity @Table(name = "AUTHORITY_") public class Authority implements Serializable { public enum Right { READ(100), WRITE(200), EDITOR (300); private int value; Right(int value) { th
@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;
}
一个简单的解决方案是将枚举注释与EnumType.ORDINAL一起使用:
@Column(name = "RIGHT")
@Enumerated(EnumType.ORDINAL)
private Right right;
但在本例中,JPA映射的是枚举索引(0,1,2),而不是我想要的值(100200300)
我发现的两个解决方案似乎并不简单
第一种解决方案
解决方案使用@PrePersist和@PostLoad将枚举转换为其他字段,并将枚举字段标记为瞬态:
@Basic
private int intValueForAnEnum;
@PrePersist
void populateDBFields() {
intValueForAnEnum = right.getValue();
}
@PostLoad
void populateTransientFields() {
right = Right.valueOf(intValueForAnEnum);
}
第二种解决方案
第二个解决方案提出了一个通用的转换对象,但看起来仍然很重并且面向hibernate(Java EE中似乎不存在@Type):
还有其他解决办法吗?
我有几个想法,但我不知道JPA中是否有:
- 加载和保存Authority对象时,请使用Authority类的右成员的setter和getter方法
- 一个等价的想法是告诉JPA什么是正确的enum方法来将enum转换为int和int转换为enum
- 因为我使用的是Spring,有没有办法告诉JPA使用特定的转换器(RightEditor)
名称,另一种是通过枚举的序号。而且标准JPA不支持自定义类型。因此:
- 如果要进行自定义类型转换,必须使用提供程序扩展(使用Hibernate
UserType
、EclipseLinkConverter
等)。(第二种解决办法)~或~
- 您必须使用@PrePersist和@PostLoad技巧(第一种解决方案)~或~
- 注释getter和setter获取并返回
int
value~或~
- 在实体级别使用整数属性,并在getter和setter中执行转换
我将说明最新的选项(这是一个基本的实现,根据需要进行调整):
对于早于JPA2.1的版本,JPA只提供了两种处理枚举的方法,通过它们的名称
或顺序
。而且标准JPA不支持自定义类型。因此:
- 如果要进行自定义类型转换,必须使用提供程序扩展(使用Hibernate
UserType
、EclipseLinkConverter
等)。(第二种解决办法)~或~
- 您必须使用@PrePersist和@PostLoad技巧(第一种解决方案)~或~
- 注释getter和setter获取并返回
int
value~或~
- 在实体级别使用整数属性,并在getter和setter中执行转换
我将说明最新的选项(这是一个基本的实现,根据需要进行调整):
可能是Pascal的密切相关代码
@Entity
@Table(name = "AUTHORITY_")
public class Authority implements Serializable {
public enum Right {
READ(100), WRITE(200), EDITOR(300);
private Integer value;
private Right(Integer value) {
this.value = value;
}
// Reverse lookup Right for getting a Key from it's values
private static final Map<Integer, Right> lookup = new HashMap<Integer, Right>();
static {
for (Right item : Right.values())
lookup.put(item.getValue(), item);
}
public Integer getValue() {
return value;
}
public static Right getKey(Integer value) {
return lookup.get(value);
}
};
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "AUTHORITY_ID")
private Long id;
@Column(name = "RIGHT_ID")
private Integer rightId;
public Right getRight() {
return Right.getKey(this.rightId);
}
public void setRight(Right right) {
this.rightId = right.getValue();
}
}
@实体
@表(name=“AUTHORITY\”)
公共类权限实现了可序列化{
公共枚举权{
读(100)、写(200)、编辑(300);
私有整数值;
私权(整数值){
这个值=值;
}
//从其值获取密钥的反向查找权限
私有静态最终映射查找=新建HashMap();
静止的{
for(右项:Right.values())
lookup.put(item.getValue(),item);
}
公共整数getValue(){
返回值;
}
公共静态右getKey(整数值){
返回lookup.get(值);
}
};
@身份证
@GeneratedValue(策略=GenerationType.AUTO)
@列(name=“AUTHORITY\u ID”)
私人长id;
@列(name=“RIGHT\u ID”)
私有整数rightId;
公共权利{
返回Right.getKey(this.rightId);
}
公共无效设置权(右){
this.rightId=right.getValue();
}
}
可能是Pascal的密切相关代码
@Entity
@Table(name = "AUTHORITY_")
public class Authority implements Serializable {
public enum Right {
READ(100), WRITE(200), EDITOR(300);
private Integer value;
private Right(Integer value) {
this.value = value;
}
// Reverse lookup Right for getting a Key from it's values
private static final Map<Integer, Right> lookup = new HashMap<Integer, Right>();
static {
for (Right item : Right.values())
lookup.put(item.getValue(), item);
}
public Integer getValue() {
return value;
}
public static Right getKey(Integer value) {
return lookup.get(value);
}
};
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "AUTHORITY_ID")
private Long id;
@Column(name = "RIGHT_ID")
private Integer rightId;
public Right getRight() {
return Right.getKey(this.rightId);
}
public void setRight(Right right) {
this.rightId = right.getValue();
}
}
@实体
@表(name=“AUTHORITY\”)
公共类权限实现了可序列化{
公共枚举权{
读(100)、写(200)、编辑(300);
私有整数值;
私权(整数值){
这个值=值;
}
//从其值获取密钥的反向查找权限
私有静态最终映射查找=新建HashMap();
静止的{
for(右项:Right.values())
lookup.put(item.getValue(),item);
}
公共整数getValue(){
返回值;
}
公共静态右getKey(整数值){
返回lookup.get(值);
}
};
@身份证
@GeneratedValue(策略=GenerationType.AUTO)
@列(name=“AUTHORITY\u ID”)
私人长id;
@列(name=“RIGHT\u ID”)
私有整数rightId;
公共权利{
返回Right.getKey(this.rightId);
}
公共无效设置权(右){
this.rightId=right.getValue();
}
}
问题是,我认为JPA从来没有想到我们可能已经有了一个复杂的预先存在的模式
我认为这导致了两个主要缺点,具体到Enum:
使用name()和ordinal()的限制。为什么不像对待@Entity那样,用@Id标记一个getter呢
Enum通常在数据库中具有表示形式,允许与各种元数据关联,包括专有名称、描述性名称,可能还有本地化名称等。我们需要Enum的易用性与实体的灵活性相结合
帮助我的事业并投票表决
这不比使用@Converter解决问题更优雅吗
// Note: this code won't work!!
// it is just a sample of how I *would* want it to work!
@Enumerated
public enum Language {
ENGLISH_US("en-US"),
ENGLISH_BRITISH("en-BR"),
FRENCH("fr"),
FRENCH_CANADIAN("fr-CA");
@ID
private String code;
@Column(name="DESCRIPTION")
private String description;
Language(String code) {
this.code = code;
}
public String getCode() {
return code;
}
public String getDescription() {
return description;
}
}
问题是,我认为,JPA从来没有想到我们可能已经有了一个复杂的预先存在的模式
我认为这导致了两个主要缺点,具体到Enum:
限制
// Note: this code won't work!!
// it is just a sample of how I *would* want it to work!
@Enumerated
public enum Language {
ENGLISH_US("en-US"),
ENGLISH_BRITISH("en-BR"),
FRENCH("fr"),
FRENCH_CANADIAN("fr-CA");
@ID
private String code;
@Column(name="DESCRIPTION")
private String description;
Language(String code) {
this.code = code;
}
public String getCode() {
return code;
}
public String getDescription() {
return description;
}
}
@Column(name = "RIGHT")
@Enumerated(EnumType.STRING)
private Right right;
public enum NodeType {
ROOT("root-node"),
BRANCH("branch-node"),
LEAF("leaf-node");
private final String code;
private NodeType(String code) {
this.code = code;
}
public String getCode() {
return code;
}
}
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
@Converter(autoApply = true)
public class NodeTypeConverter implements AttributeConverter<NodeType, String> {
@Override
public String convertToDatabaseColumn(NodeType nodeType) {
return nodeType.getCode();
}
@Override
public NodeType convertToEntityAttribute(String dbData) {
for (NodeType nodeType : NodeType.values()) {
if (nodeType.getCode().equals(dbData)) {
return nodeType;
}
}
throw new IllegalArgumentException("Unknown database value:" + dbData);
}
}
@Column(name = "node_type_code")
public enum RightEnum {
READ(100), WRITE(200), EDITOR (300);
private int value;
private RightEnum (int value) { this.value = value; }
@Override
public static Etapa valueOf(Integer value){
for( RightEnum r : RightEnum .values() ){
if ( r.getValue().equals(value))
return r;
}
return null;//or throw exception
}
public int getValue() { return value; }
}
@Entity
public class Right{
@Id
private Integer id;
//FIElDS
// constructor
public Right(RightEnum rightEnum){
this.id = rightEnum.getValue();
}
public Right getInstance(RightEnum rightEnum){
return new Right(rightEnum);
}
}
import mypackage.RightEnum;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
/**
*
*
*/
@Converter(autoApply = true)
public class RightEnumConverter implements AttributeConverter<RightEnum, Integer>{
@Override //this method shoudn´t be used, but I implemented anyway, just in case
public Integer convertToDatabaseColumn(RightEnum attribute) {
return attribute.getValue();
}
@Override
public RightEnum convertToEntityAttribute(Integer dbData) {
return RightEnum.valueOf(dbData);
}
}
@Entity
@Table(name = "AUTHORITY_")
public class Authority implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "AUTHORITY_ID")
private Long id;
// the **Entity** to map :
private Right right;
// the **Enum** to map (not to be persisted or updated) :
@Column(name="COLUMN1", insertable = false, updatable = false)
@Convert(converter = RightEnumConverter.class)
private RightEnum rightEnum;
}
autorithy.setRight( Right.getInstance( RightEnum.READ ) );//for example
authority.getRight().equals( RightEnum.READ ); //for example
public enum RightEnum {
READ(100), WRITE(200), EDITOR (300);
private int value;
private RightEnum (int value) {
try {
this.value= value;
final Field field = this.getClass().getSuperclass().getDeclaredField("ordinal");
field.setAccessible(true);
field.set(this, value);
} catch (Exception e) {//or use more multicatch if you use JDK 1.7+
throw new RuntimeException(e);
}
}
@Override
public static Etapa valueOf(Integer value){
for( RightEnum r : RightEnum .values() ){
if ( r.getValue().equals(value))
return r;
}
return null;//or throw exception
}
public int getValue() { return value; }
}
@Entity
@Table(name = "AUTHORITY_")
public class Authority implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "AUTHORITY_ID")
private Long id;
// the **Enum** to map (to be persisted or updated) :
@Column(name="COLUMN1")
@Enumerated(EnumType.ORDINAL)
private RightEnum rightEnum;
}