Java 使用枚举作为id

Java 使用枚举作为id,java,jpa,openjpa,Java,Jpa,Openjpa,使用JPA,我们可以将枚举定义为实体的id吗 我尝试了以下方法: public enum AssetType { .... } @Entity @IdClass(AssetType.class) public class Adkeys { private AssetType type; @Id @Enumerated(EnumType.STRING) @Column(nullable = false) public AssetType getType()

使用JPA,我们可以将枚举定义为实体的id吗

我尝试了以下方法:

public enum AssetType {
   ....
}

@Entity
@IdClass(AssetType.class)
public class Adkeys {

   private AssetType type;

   @Id
   @Enumerated(EnumType.STRING)
   @Column(nullable = false)
   public AssetType getType() {
      return type;
   }

}
使用OpenJPA,它抱怨:

org.apache.openjpa.persistence.ArgumentException:由类型“class aa.Adkeys”指定的id类“class aa.AssetType”没有公共的无参数构造函数

因此,我的问题是:

  • 我们应该能够使用枚举作为JPA上实体的id吗?(即OpenJPA中有一个bug)
  • 还是我在某个地方犯了错误
  • 有没有解决这个问题的办法

    • JPA规范没有说这是可能的:

      2.1.4主键和实体标识

      主键(或复合主键的字段或属性)应该是以下类型之一:任何Java基元类型;任何原始包装类型;java.lang.String;java.util.Date;java.sql.Date。但是,一般来说,主键中不应使用近似数字类型(例如浮点类型)。主键使用其他类型的实体将不可移植

      如果您确实希望为给定实体拥有编译时固定数量的记录,则可以使用
      字符串
      int
      主键并将其分配给
      AssetType.FOO.name()
      AssetType.FOO.ordinal()


      这里的不可移植意味着某些持久性提供程序可能支持其他东西,但它可能不适用于其他提供程序。与枚举一样,如果持久性提供程序对它有特殊的支持,它不会尝试实例化它,而是在检查
      class.isEnum()
      之后专门处理它,那么它可能会工作。但您的持久性提供程序似乎没有做到这一点。

      不,您不能使用枚举作为ID,因为JPA不允许为ID列定义自己的映射(它们必须是
      int
      long
      或JPA可以使用
      new
      创建的内容)

      ID不能是业务密钥(在您的情况下:类型)。使用业务密钥作为ID是DB设计中的一个常见错误,应该避免,因为它会在以后导致各种问题


      添加一个独立的ID列以解决此问题。

      是否确实要执行此操作?此构造不允许在不更新代码中的枚举(加载失败)的情况下更改数据库枚举键,反之亦然(约束失败)。为什么不创建一个带有int pk和name的AssetType表,并让AdKey有一个AssetType.id的外键作为pk


      如果需要在应用程序中枚举资产类型,可以在启动时从db加载这些资产类型。

      OpenJPA是唯一不支持此操作的JPA提供程序。

      @Nathan:那么它一定是一个bug。它没有说这是可能的,但也没有说这是不可能的。它只是说:“主键使用其他类型的实体将不可移植”。事实上,它也没有说类可以用作主键,但这是可能的。这是另一件事-一个可嵌入的id。有关可移植性部分,请参阅我的更新。因此,我想这是一个有效的增强请求,你不认为吗?@Enumerated(EnumType.STRING)这不意味着列将作为字符串值持久化吗?是的,所以应该可以将其用作@Id列。在某些情况下,表中的条目不多,需要按字符串引用。数字Id是最常用的方式,但如果使用正确,其他数据类型也不会出错!添加到真相来源的链接会很有帮助。我正在使用旧数据库。当然,我可以改变它,但它可能会有问题。枚举只是一堆固定值。我正在处理旧数据库。这可能不是一个好的设计,但它就在那里。枚举只是一组刚性值。