Java 如何将枚举与JPA一起使用
我有一个电影租赁系统的现有数据库。每部电影都有一个等级属性。在SQL中,他们使用约束来限制此属性的允许值Java 如何将枚举与JPA一起使用,java,jpa,enums,toplink,Java,Jpa,Enums,Toplink,我有一个电影租赁系统的现有数据库。每部电影都有一个等级属性。在SQL中,他们使用约束来限制此属性的允许值 CONSTRAINT film_rating_check CHECK ((((((((rating)::text = ''::text) OR ((rating)::text = 'G'::text)) OR ((rating)::text = 'PG'::text)) OR ((rating)::text = 'P
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()方法时,方向enum->String可以正常工作,但String->enum不起作用。我得到以下例外情况:
[TopLink警告]:2008.12.09
01:30:57.434--服务器会话(4729123)--异常[TOPLINK-116](Oracle)
TopLink Essentials-2.0.1(构建b09d fcs(12/06/2007)):
oracle.toplink.essentials.exceptions.DescriptorException异常
说明:中的值[NC-17]未提供转换值
现场[电影分级]。映射:
oracle.toplink.essentials.mappings.DirectToFieldMapping[rating-->FILM.rating]
描述符:关系描述符(de.fhw.nsdb.entities.Film-->
[数据库表(胶片)])
干杯
timo我不知道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。这是怎么回事
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;
}
这样,您可以在数据库和实体上使用分级作为字符串,但在其他所有内容中都使用枚举。public enum Rating{
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;
}
}
未评级(“”),
G(“G”),
PG(“PG”),
第13页(“第13页”),
R(“R”),
NC17(“NC-17”);
私人字符串评级;
私有静态映射评级=新HashMap();
静止的{
for(评级r:EnumSet.allOf(评级.class)){
ratings.put(r.toString(),r);
}
}
私有静态评级getRating(字符串评级){
返回评级。获取(评级);
}
私人评级(字符串评级){
这个。评级=评级;
}
@凌驾
公共字符串toString(){
回报率;
}
}
但是,我不知道如何在带有注释的TopLink端进行映射。听起来您需要添加对自定义类型的支持:
这里有一个问题,那就是JPA在处理枚举时的能力有限。使用枚举,您有两种选择:
Enum.ordinal()
的数字,这是一个糟糕的想法(imho);或Enum.name()
注意:不像您预期的那样toString()
,特别是因为Enum.toString()
的默认行为是返回name()
- 更改您的数据李>
- 持久化字符串字段,并隐式地将它们转换为对象中的枚举或从中转换;或
- 使用诸如TypeConverter之类的非标准扩展
作为另一个建议,我强烈建议改为。这是一个比Toplink Essentials更为完整的实现,Eclipselink将在发布时作为JPA 2.0的参考实现(预计于明年中由JavaOne发布)。您是否尝试存储序号值。如果没有与该值关联的字符串,则存储字符串值可以正常工作:
@Enumerated(EnumType.ORDINAL)
使用此注释
@Column(columnDefinition="ENUM('User', 'Admin')")
决心!!!
在那里我找到了答案:
简单地说,转换查找的是enum的名称,而不是属性“rating”的值。
在您的情况下:如果在db值“NC-17”中有,则需要在枚举中有:
枚举评级{(…)
NC-17(“NC-17”);
(…)
问题是,我认为,JPA从来没有想到我们可能已经有了一个复杂的预先存在的模式 我认为这导致了两个主要缺点,具体到Enum:
public int compare(final ParentalControlLevelsEnum o1, final ParentalControlLevelsEnum o2) {
if (o1.ordinal() < o2.ordinal()) {
return -1;
} else {
return 1;
}
}
public int compare(最终ParentalControlLevelsEnum o1,最终ParentalControlLevelsEnum o2){
if(o1.ordinal()
}使用您现有的
枚举评级
。您可以使用属性转换器
s
@转换器(autoApply=true)
公共类RatingConverter实现AttributeConverter{
@凌驾
公共字符串convertToDatabaseColumn(额定值){
如果(额定值==null){
返回null;
}
返回评级。toString();
}
@凌驾
公共评级convertToEntityAttribute(字符串代码){
如果(代码==null){
返回null;
}
回流(
public int compare(final ParentalControlLevelsEnum o1, final ParentalControlLevelsEnum o2) {
if (o1.ordinal() < o2.ordinal()) {
return -1;
} else {
return 1;
}
}