我有一个电影租赁系统的现有数据库。每部电影都有一个评级属性。在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 - >枚举不起作用。我得到以下异常:
欢呼[TopLink警告]:2008.12.09 01:30:57.434 - ServerSession(4729123) - 例外[TOPLINK-116](Oracle TopLink Essentials - 2.0.1(Build b09d-fcs(12/06/2007))): oracle.toplink.essentials.exceptions.DescriptorException异常 说明:没有为[NC-17]中的值提供转换值 字段[FILM.RATING]。制图: oracle.toplink.essentials.mappings.DirectToFieldMapping [评级 - > FILM.RATING] 描述符:RelationalDescriptor(de.fhw.nsdb.entities.Film - > [DatabaseTable(FILM)])
蒂莫
答案 0 :(得分:28)
您是否尝试存储序数值?如果您没有关联的String值,则存储字符串值可以正常工作:
@Enumerated(EnumType.ORDINAL)
答案 1 :(得分:24)
这里有一个问题,那就是处理枚举时JPA的功能有限。使用枚举,您有两种选择:
Enum.ordinal()
的数字,这是一个糟糕的主意(imho);或Enum.name()
的字符串。 注意:不是您所期望的toString()
,尤其是因为Enum.toString()
的默认行为是返回name()
。我个人认为最好的选择是(2)。
现在您遇到的问题是,您定义的值不代表Java中的vailid实例名称(即使用连字符)。所以你的选择是:
我会按顺序(从头到尾)按顺序排列。
有人建议使用Oracle TopLink的转换器,但您可能正在使用Toplink Essentials,作为参考JPA 1.0实现,它是商业Oracle Toplink产品的一个子集。
作为另一个建议,我强烈建议切换到EclipseLink。这是一个比Toplink Essentials更完整的实现,Eclipselink将成为JPA 2.0的参考实现(预计将于明年年中推出)。
答案 2 :(得分:7)
听起来您需要添加对自定义类型的支持:
Extending OracleAS TopLink to Support Custom Type Conversions
答案 3 :(得分:5)
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方面做映射。
答案 4 :(得分:2)
我不知道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。
答案 5 :(得分:1)
我认为问题在于,JPA从未接受过这样的想法,即我们可能已经有一个复杂的预先存在的Schema。
我认为这有两个主要缺点,特别是Enum:
帮助我的事业并在JPA_SPEC-47
上投票答案 6 :(得分:0)
这个怎么样?
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;
}
这样你就可以在数据库和实体上使用等级作为字符串,但是将枚举用于其他所有内容。
答案 7 :(得分:0)
使用现有的enum Rating
。您可以使用AttributeCoverter
。
@Converter(autoApply = true)
public class RatingConverter implements AttributeConverter<Rating, String> {
@Override
public String convertToDatabaseColumn(Rating rating) {
if (rating == null) {
return null;
}
return rating.toString();
}
@Override
public Rating convertToEntityAttribute(String code) {
if (code == null) {
return null;
}
return Stream.of(Rating.values())
.filter(c -> c.toString().equals(code))
.findFirst()
.orElseThrow(IllegalArgumentException::new);
}
}
答案 8 :(得分:-1)
使用此注释
@Column(columnDefinition="ENUM('User', 'Admin')")
答案 9 :(得分:-1)
枚举 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;
}
}
比较 - &gt;枚举
公共类RatingComparator实现Comparator {
public int compare(final ParentalControlLevelsEnum o1, final ParentalControlLevelsEnum o2) {
if (o1.ordinal() < o2.ordinal()) {
return -1;
} else {
return 1;
}
}
}
答案 10 :(得分:-2)
解决!!! 在哪里我找到答案:http://programming.itags.org/development-tools/65254/
简而言之,转换会查找枚举的名称,而不是属性“rating”的值。 在你的情况下:如果你有db值“NC-17”,你需要有你的枚举:
枚举评分{
(...)
NC-17 (“NC-17”);
(...)