Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use enums with JPA

I have an existing database of a film rental system. Each film has a has a rating attribute. In SQL they used a constraint to limit the allowed values of this attribute.

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))) 

I think it would be nice to use a Java enum to map the constraint into the object world. But it's not possible to simply take the allowed values because of the special char in "PG-13" and "NC-17". So I implemented the following enum:

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

With the toString() method the direction enum -> String works fine, but String -> enum does not work. I get the following exception:

[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.DescriptorException Exception Description: No conversion value provided for the value [NC-17] in field [FILM.RATING]. Mapping: oracle.toplink.essentials.mappings.DirectToFieldMapping[rating-->FILM.RATING] Descriptor: RelationalDescriptor(de.fhw.nsdb.entities.Film --> [DatabaseTable(FILM)])

cheers

timo

like image 360
Timo Avatar asked Dec 09 '08 12:12

Timo


People also ask

How do I map an enum to a column in a database?

To map the Enum to a String database column type, you need to specify the EnumType. STRING value when using the @Enumerated annotation. As expected, the String representation of the Java Enum was used to populate the associated database column value.

What is the default enum value type in JPA?

JPA & Hibernate Standard Enum Mappings By default, Hibernate maps an enum to a number. It uses the ordinal value, which is the zero-based position of a value within the definition of the enum. So, the enum value that's defined first gets mapped to 0, the second one to 1 and so on.

Which annotation in JPA may be used to specify whether enum should be persisted as number in database column?

The @Enumerated annotation enables you to define how an enum attribute gets persisted in the database. By default, all JPA implementations map the ordinal value of the enum to a numeric database column.


2 Answers

have you tried to store the ordinal value. Store the string value works fine if you don't have an associated String to the value:

@Enumerated(EnumType.ORDINAL) 
like image 127
aledbf Avatar answered Sep 19 '22 18:09

aledbf


You have a problem here and that is the limited capabilities of JPA when it comes to handling enums. With enums you have two choices:

  1. Store them as a number equalling Enum.ordinal(), which is a terrible idea (imho); or
  2. Store them as a string equalling Enum.name(). Note: not toString() as you might expect, especially since the default behaviourfor Enum.toString() is to return name().

Personally I think the best option is (2).

Now you have a problem in that you're defining values that don't represent vailid instance names in Java (namely using a hyphen). So your choices are:

  • Change your data;
  • Persist String fields and implicitly convert them to or from enums in your objects; or
  • Use nonstandard extensions like TypeConverters.

I would do them in that order (first to last) as an order of preference.

Someone suggested Oracle TopLink's converter but you're probably using Toplink Essentials, being the reference JPA 1.0 implementation, which is a subset of the commercial Oracle Toplink product.

As another suggestion, I'd strongly recommend switching to EclipseLink. It is a far more complete implementation than Toplink Essentials and Eclipselink will be the reference implementation of JPA 2.0 when released (expected by JavaOne mid next year).

like image 21
cletus Avatar answered Sep 23 '22 18:09

cletus