使用enum作为id

时间:2010-09-15 12:48:32

标签: 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() {
      return type;
   }

}

使用OpenJPA,它抱怨:

  

org.apache.openjpa.persistence.ArgumentException:由类“class aa.Adkeys”指定的id类“class aa.AssetType”没有公共的no-args构造函数。

所以我的问题是:

  • 我们是否应该使用枚举作为JPA上实体的id? (即OpenJPA中存在错误)
  • 或者我在某处犯了错误?
  • 是否有针对此类问题的解决方法?

4 个答案:

答案 0 :(得分:7)

JPA规范并未说明这是可能的:

  

2.1.4主键和实体标识

     

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

如果您确实希望为给定实体提供编译时固定数量的记录,则可以使用Stringint主键并为其分配AssetType.FOO.name()或{{ 1}}

此处不可移植意味着某些持久性提供程序可能支持其他内容,但它可能不适用于其他提供程序。与枚举一样 - 如果持久性提供程序对它有特殊支持,那么它不会尝试实例化它,而是在检查AssetType.FOO.ordinal()后是否特别处理它,然后它可能会起作用。但似乎你的持久性提供者不会这样做。

答案 1 :(得分:4)

不,您不能将枚举用作ID,因为JPA不允许为ID列定义您自己的映射(它们必须是intlong或JPA可以使用{ {1}})。

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

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

答案 2 :(得分:2)

OpenJPA是唯一不支持此功能的JPA提供商。 见Support Enum as Primary Key Type

答案 3 :(得分:0)

你真的想这样做吗?此构造不允许更改数据库枚举键而不更新代码中的枚举(加载失败),也不允许更改数据库枚举键(约束失败)。你为什么不用int pk和name创建一个AssetType表,并让Adkeys有一个外键到AssetType.id作为pk?

如果您需要在应用中枚举它们,可以在启动时从数据库加载AssetTypes。