如何在JPA中使用枚举

我有一个电影租赁系统的现有数据库。 每部电影都有一个评级属性。 在SQL中,他们使用一个约束来限制这个属性的允许值。

CONSTRAINT film_rating_check CHECK ((((((((rating)::text = ''::text) OR ((rating)::text = 'G'::text)) OR ((rating)::text = 'PG'::text)) OR ((rating)::text = 'PG-13'::text)) OR ((rating)::text = 'R'::text)) OR ((rating)::text = 'NC-17'::text))) 

我认为使用Java枚举将约束映射到对象世界将会很好。 但是由于“PG-13”和“NC-17”中的特殊字符,不可能简单地取得所允许的值。 所以我实现了以下枚举:

 public enum Rating { UNRATED ( "" ), G ( "G" ), PG ( "PG" ), PG13 ( "PG-13" ), R ( "R" ), NC17 ( "NC-17" ); private String rating; private Rating(String rating) { this.rating = rating; } @Override public String toString() { return rating; } } @Entity public class Film { .. @Enumerated(EnumType.STRING) private Rating rating; .. 

使用toString()方法的方向枚举 – >string正常工作,但string – >枚举不起作用。 我得到以下例外:

[TopLink Warning]:2008.12.09 01:30:57.434 – ServerSession(4729123) – exception[TOPLINK-116](Oracle TopLink Essentials – 2.0.1(Build b09d-fcs(12/06/2007))) oracle.toplink.essentials.exceptions.DescriptorExceptionexception说明:没有为字段[FILM.RATING]中的值[NC-17]提供转换值。 映射:oracle.toplink.essentials.mappings.DirectToFieldMapping [rating – > FILM.RATING]描述符:RelationalDescriptor(de.fhw.nsdb.entities.Film – > [DatabaseTable(FILM)])

干杯

蒂莫

听起来像你需要添加对自定义types的支持:

扩展OracleAS TopLink以支持自定义types转换

你有没有尝试存储序数值? 如果您没有关联的string值,则存储string值可以正常工作:

 @Enumerated(EnumType.ORDINAL) 

这里有一个问题,那就是JPA在处理枚举时的能力有限。 有了枚举,你有两个select:

  1. 将它们存储为等于Enum.ordinal() ,这是一个可怕的想法(imho); 要么
  2. 将它们存储为一个等于Enum.name()的string。 注意:不要像toString()那样,尤其是因为Enum.toString()的默认行为是返回name()

我个人认为最好的select是(2)。

现在你有一个问题,你正在定义的值不代表Java中的vilid实例名(即使用连字符)。 所以你的select是:

  • 改变你的数据;
  • 坚持string字段,并将它们隐式转换为对象中的枚举或从其中枚举。 要么
  • 使用像TypeConverters这样的非标准扩展。

我会按顺序(首先到最后)按顺序来做。

有人build议使用Oracle TopLink的转换器,但是您可能使用的是Toplink Essentials,这是参考JPA 1.0实现,它是商业Oracle Toplink产品的子集。

作为另一个build议,我强烈build议切换到EclipseLink 。 这是一个比Toplink Essentials更完整的实现,Eclipselink将会是JPA 2.0的参考实现(JavaOne明年年中预计)。

 public enum Rating { UNRATED ( "" ), G ( "G" ), PG ( "PG" ), PG13 ( "PG-13" ), R ( "R" ), NC17 ( "NC-17" ); private String rating; private static Map<String, Rating> ratings = new HashMap<String, Rating>(); static { for (Rating r : EnumSet.allOf(Rating.class)) { ratings.put(r.toString(), r); } } private static Rating getRating(String rating) { return ratings.get(rating); } private Rating(String rating) { this.rating = rating; } @Override public String toString() { return rating; } } 

但是我不知道如何去做注释的TopLink方面的映射。

我不知道toplink的内部结构,但是我的教育猜测如下:它使用Rating.valueOf(String s)方法映射到另一个方向。 不可能重写valueOf(),所以你必须坚持java的命名约定,以允许一个正确的valueOf方法。

 public enum Rating { UNRATED, G, PG, PG_13 , R , NC_17 ; public String getRating() { return name().replace("_","-");; } } 

getRating产生“人类可读”的评级。 请注意,枚举标识符中不允许使用“ – ”字符。

当然,你将不得不把这些值存储在数据库中作为NC_17。

问题是,我认为,JPA从来没有考虑到这个想法,我们可能已经有了一个复杂的已经存在的Schema。

我认为这有两个主要缺点,具体到Enum:

  1. 使用name()和ordinal()的限制。 为什么不用@Id标记一个getter,就像我们用@Entity做的那样?
  2. Enum在数据库中通常具有表示forms以允许与各种元数据关联,包括专有名称,描述性名称,可能与本地化等有关的内容。我们需要Enum的简单易用性和实体的灵活性。

帮助我的事业并对JPA_SPEC-47进行投票

那这个呢

 public String getRating{ return rating.toString(); } pubic void setRating(String rating){ //parse rating string to rating enum //JPA will use this getter to set the values when getting data from DB } @Transient public Rating getRatingValue(){ return rating; } @Transient public Rating setRatingValue(Rating rating){ this.rating = rating; } 

用这个你可以在你的数据库和实体上使用String作为string,但是使用enum作为其他的东西。

使用这个注解

 @Column(columnDefinition="ENUM('User', 'Admin')") 

Enum public enum ParentalControlLevelsEnum {U(“U”),PG(“PG”),_12(“12”),_15(“15”),_18(“18”);

 private final String value; ParentalControlLevelsEnum(final String value) { this.value = value; } public String getValue() { return value; } public static ParentalControlLevelsEnum fromString(final String value) { for (ParentalControlLevelsEnum level : ParentalControlLevelsEnum.values()) { if (level.getValue().equalsIgnoreCase(value)) { return level; } } return null; } 

}

比较 – >枚举

公共类RatingComparator实现比较器{

 public int compare(final ParentalControlLevelsEnum o1, final ParentalControlLevelsEnum o2) { if (o1.ordinal() < o2.ordinal()) { return -1; } else { return 1; } } 

}

解决!!! 我在哪find答案: http : //programming.itags.org/development-tools/65254/

简单地说,转换查找枚举的名称,而不是属性“评级”的值。 在你的情况:如果你有在分贝值“NC-17”,你需要在你的枚举:

枚举评级{
(……)
NC-17 (“NC-17”);
(……)