代码之家  ›  专栏  ›  技术社区  ›  Timo

如何将枚举与JPA一起使用

  •  34
  • Timo  · 技术社区  · 17 年前

    我有一个电影租赁系统的现有数据库。每部电影都有一个等级属性。在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;
        ..
    

    [TopLink警告]:2008.12.09 TopLink Essentials-2.0.1(构建b09d fcs(12/06/2007)): oracle.toplink.essentials.exceptions.DescriptorException异常 现场[电影分级]。映射: 描述符:关系描述符(de.fhw.nsdb.entities.Film-->

    干杯

    蒂莫

    10 回复  |  直到 11 年前
        1
  •  31
  •   aledbf    17 年前

    您是否尝试存储序号值。如果没有与该值关联的字符串,则存储字符串值可以正常工作:

    @Enumerated(EnumType.ORDINAL)
    
        2
  •  25
  •   cletus    17 年前

    这里有一个问题,那就是JPA在处理枚举时的能力有限。使用枚举,您有两种选择:

    1. Enum.ordinal() ,这是一个糟糕的想法(imho);或
    2. 将它们存储为相等的字符串 Enum.name() 注: toString() Enum.toString() 就是回来 name() .

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

    • 更改您的数据;
    • 持久化字符串字段,并隐式地将它们转换为对象中的枚举或从中转换;或

    我会按照优先顺序(从早到晚)做。

    另一个建议是,我强烈建议改为 EclipseLink . 这是一个比ToplinkEssentials更完整的实现,Eclipselink将在发布时作为JPA2.0的参考实现(预计JavaOne将于明年中期发布)。

        4
  •  5
  •   JeeBee    17 年前
    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端进行映射。

        5
  •  2
  •   Andreas Petersson    17 年前

    我不知道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生成“人类可读”评级。请注意,枚举标识符中不允许使用“-”字符。

        6
  •  1
  •   Martin    7 年前

    问题是,我认为,JPA从来没有想到我们可能已经有了一个复杂的预先存在的模式。

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

    1. Enum通常在数据库中具有表示形式,允许与各种元数据关联,包括专有名称、描述性名称,可能还有本地化名称等。我们需要Enum的易用性与实体的灵活性相结合。

    帮助我的事业并投票表决 JPA_SPEC-47

        7
  •  0
  •   Mg.    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;
    }
    

        8
  •  0
  •   Archimedes Trajano    6 年前

    使用现有的 enum Rating . 你可以用 AttributeCoverter s

    @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);
        }
    }
    
        9
  •  -1
  •   Selvaraj Muthiah    15 年前

    使用此注释

    @Column(columnDefinition="ENUM('User', 'Admin')")
    
        10
  •  -1
  •   Jayen Chondigara    8 年前

    枚举 公共枚举ParentalControlLevelsEnum{

    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;
    }
    

    }

    比较->枚举

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

    }

        11
  •  -2
  •   pingpong    14 年前

    断然的!!! 在那里我找到了答案: http://programming.itags.org/development-tools/65254/

    简单地说,转换查找的是enum的名称,而不是属性“rating”的值。

    枚举评级{

    (“NC-17”);