Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用固定值映射JPA中的枚举?_Java_Spring_Orm_Jpa_Enums - Fatal编程技术网

Java 使用固定值映射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

我正在寻找使用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) { 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)

对于JPA2.1之前的版本,JPA只提供了两种处理枚举的方法,一种是通过枚举的
名称,另一种是通过枚举的
序号。而且标准JPA不支持自定义类型。因此:

  • 如果要进行自定义类型转换,必须使用提供程序扩展(使用Hibernate
    UserType
    、EclipseLink
    Converter
    等)。(第二种解决办法)~或~
  • 您必须使用@PrePersist和@PostLoad技巧(第一种解决方案)~或~
  • 注释getter和setter获取并返回
    int
    value~或~
  • 在实体级别使用整数属性,并在getter和setter中执行转换
我将说明最新的选项(这是一个基本的实现,根据需要进行调整):


对于早于JPA2.1的版本,JPA只提供了两种处理枚举的方法,通过它们的
名称
或顺序
。而且标准JPA不支持自定义类型。因此:

  • 如果要进行自定义类型转换,必须使用提供程序扩展(使用Hibernate
    UserType
    、EclipseLink
    Converter
    等)。(第二种解决办法)~或~
  • 您必须使用@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;
    
    }