example column java jpa enums toplink

java - column - jsf jpa crud



Cómo usar enumeraciones con JPA (10)

¡¡¡Resuelto!!! Donde encontré la respuesta: http://programming.itags.org/development-tools/65254/

En resumen, la conversión busca el nombre de enum, no el valor del atributo ''calificación''. En su caso: si tiene los valores db "NC-17", debe tener en su enumeración:

enum Rating {
(...)
NC-17 ("NC-17");
(...)

Tengo una base de datos existente de un sistema de alquiler de películas. Cada película tiene un atributo de calificación. En SQL, usaron una restricción para limitar los valores permitidos de este atributo.

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

Creo que sería bueno usar una enumeración Java para mapear la restricción en el mundo de los objetos. Pero no es posible simplemente tomar los valores permitidos debido a la char especial en "PG-13" y "NC-17". Así que implementé la siguiente enumeración:

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

Con el método toString () la dirección enum -> String funciona bien, pero String -> enum no funciona. Obtengo la siguiente excepción:

[Advertencia de TopLink]: 2008.12.09 01: 30: 57.434 - ServerSession (4729123) - Excepción [TOPLINK-116] (Oracle TopLink Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))): oracle.toplink.essentials.exceptions.DescriptorException Excepción Descripción: No se proporcionó valor de conversión para el valor [NC-17] en el campo [FILM.RATING]. Asignación: oracle.toplink.essentials.mappings.DirectToFieldMapping [clasificación -> FILM.RATING] Descriptor: RelationalDescriptor (de.fhw.nsdb.entities.Film -> [DatabaseTable (FILM)])

aclamaciones

timo


Aquí tienes un problema y esas son las capacidades limitadas de JPA cuando se trata de manejar enumeraciones. Con enumeraciones tienes dos opciones:

  1. Guárdelos como un número igual a Enum.ordinal() , que es una idea terrible (imho); o
  2. Guárdelos como una cadena que iguala Enum.name() . Nota: no toString() como cabría esperar, especialmente porque el comportamiento predeterminado para Enum.toString() es devolver el name() .

Personalmente, creo que la mejor opción es (2).

Ahora tiene un problema porque está definiendo valores que no representan los nombres de instancia de vailid en Java (es decir, que usan un guión). Entonces tus elecciones son:

  • Cambia tus datos;
  • Persistir los campos String e implícitamente convertirlos ao desde enumeraciones en sus objetos; o
  • Use extensiones no estándar como TypeConverters.

Los haría en ese orden (primero al último) como un orden de preferencia.

Alguien sugirió el conversor de Oracle TopLink, pero probablemente esté utilizando Toplink Essentials, que es la implementación de referencia de JPA 1.0, que es un subconjunto del producto comercial Oracle Toplink.

Como otra sugerencia, recomiendo cambiar a EclipseLink . Es una implementación mucho más completa que Toplink Essentials y Eclipselink será la implementación de referencia de JPA 2.0 una vez lanzada (prevista por JavaOne a mediados del próximo año).


El problema es que, creo, que JPA nunca tuvo en cuenta la idea en mente de que podríamos tener un esquema preexistente complejo ya en su lugar.

Creo que hay dos deficiencias principales que resultan de esto, específicas de Enum:

  1. La limitación de usar name () y ordinal (). ¿Por qué no solo marca un getter con @Id, de la misma manera que hacemos con @Entity?
  2. Enum generalmente tienen representación en la base de datos para permitir la asociación con todo tipo de metadatos, incluyendo un nombre propio, un nombre descriptivo, tal vez algo con localización, etc. Necesitamos la facilidad de uso de un Enum combinado con la flexibilidad de una Entidad.

Ayuda a mi causa y vota en JPA_SPEC-47


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

}

comparar -> Enum

clase pública RatingComparator implementa Comparator {

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

}



Que tal esto

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

con esto usas las clasificaciones como String tanto en tu DB como en tu entidad, pero usa la enumeración para todo lo demás.


has intentado almacenar el valor ordinal. Almacenar el valor de cadena funciona bien si no tiene una cadena asociada al valor:

@Enumerated(EnumType.ORDINAL)


no conozco las partes internas de toplink, pero mi conjetura es la siguiente: utiliza el método Rating.valueOf (String s) para mapear en la otra dirección. no es posible anular valueOf (), por lo que debe apegarse a la convención de nomenclatura de java, para permitir un método valueOf correcto.

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

getRating produce la calificación de "lectura humana". tenga en cuenta que el carácter "-" no está permitido en el identificador enum.

por supuesto, tendrá que almacenar los valores en el DB como NC_17.


usa esta anotación

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


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

Sin embargo, no sé cómo hacer las asignaciones en el lado anotado de TopLink.