Frage

Ich habe eine vorhandene Datenbank eines Filmverleihsystem. Jeder Film hat ein ein Rating-Attribut verfügt. In SQL verwendet sie eine Einschränkung der zulässigen Werte dieses Attributs zu begrenzen.

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

ich denke, es wäre schön, einen Java-Enumeration zu verwenden, um die Einschränkung in die Objektwelt abzubilden. Aber es ist nicht möglich, einfach die zulässigen Werte nimmt wegen der speziellen Zeichen in „PG-13“ und „NC-17“. So implementiert ich die folgende Enumeration:

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

Mit der Methode toString () die Richtung Enum -> String funktioniert gut, aber String -> ENUM funktioniert nicht. Ich erhalte die folgende Ausnahme:

  

[TopLink Warnung]: 2008.12.09   01: 30: 57,434 - Serversession (4.729.123) - Ausnahme [TOPLINK-116] (Oracle   TopLink-Grundlagen - 2.0.1 (Build b09d-FKS (12.06.2007))):   oracle.toplink.essentials.exceptions.DescriptorException Exception   Beschreibung: Kein Umrechnungswert für den Wert zur Verfügung gestellt [NC-17] in   Feld [FILM.RATING]. Kartierung:   oracle.toplink.essentials.mappings.DirectToFieldMapping [Bewertung -> FILM.RATING]   Descriptor: RelationalDescriptor (de.fhw.nsdb.entities.Film ->   [Databasetable (FILM)])

cheers

timo

War es hilfreich?

Lösung

Klingt wie Sie Unterstützung für eine benutzerdefinierte Typ hinzufügen müssen:

erweitern OracleAS TopLink Benutzerdefinierte Typkonvertierungen zur Unterstützung

Andere Tipps

Sie haben den Ordnungswert zu speichern versucht. Bewahren Sie den String-Wert funktioniert gut, wenn Sie nicht über einen zugeordneten String auf den Wert haben:

@Enumerated(EnumType.ORDINAL)

Sie haben hier ein Problem, und das sind die begrenzten Möglichkeiten von PPV, wenn es um die Handhabung Aufzählungen kommt. Mit Aufzählungen haben Sie zwei Möglichkeiten:

  1. Speichern Sie sie als Zahl gleich Enum.ordinal(), die eine schreckliche Idee ist (imho); oder
  2. Speichern Sie sie als String gleich Enum.name(). . Hinweis: nicht toString() wie man erwarten könnte, zumal der Standard behaviourfor Enum.toString() zurückzukehren name() ist

Ich persönlich denke, die beste Option ist (2).

Jetzt haben Sie ein Problem, dass Sie Werte sind definiert, die nicht vailid Instanznamen in Java darstellen kann (nämlich einen Bindestrich verwendet wird). So haben Sie folgende Möglichkeiten:

  • Ändern Sie Ihre Daten;
  • Persist Felder String und sie implizit oder von Aufzählungen in Ihren Objekten konvertieren; oder
  • Verwenden Sie Nicht-Standard-Erweiterungen wie Typeconverter.

Ich würde sie in dieser Reihenfolge tun (Anfang bis Ende) als Reihenfolge der Präferenz.

Jemand schlug Oracle TopLink des Konverters aber Sie verwenden wahrscheinlich Toplink Essentials der PPV Referenz 1.0 Implementierung ist, die eine Teilmenge der kommerziellen Oracle Toplink Produkt ist.

Als weiteren Vorschlag, würde ich dringend empfehlen Schalt Eclipse . Es ist eine weit umfangreichere Umsetzung als Toplink Essentials und Eclipse wird die Referenz-Implementierung von JPA 2.0 sein, wenn sie freigegeben (von JavaOne Mitte nächstes Jahr erwartet).

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

Ich weiß nicht, wie die Zuordnungen in der kommentierten TopLink Seite der Dinge jedoch zu tun.

Ich weiß nicht, Interna von toplink, aber meine fundierten Vermutung ist folgende: es die Rating.valueOf (String s) -Methode verwendet in der anderen Richtung zu kartieren. es ist nicht möglich, valueOf () außer Kraft zu setzen, so dass Sie auf die Namenskonvention von Java-Stick muss, um eine korrekte valueOf Methode zu ermöglichen.

public enum Rating {

    UNRATED,
    G, 
    PG,
    PG_13 ,
    R ,
    NC_17 ;

    public String getRating() {
        return name().replace("_","-");;
    }
}

getRating produziert die „Menschen lesbare“ -Rating. beachten Sie, dass die "-". Chanracter nicht in der ENUM-Kennung erlaubt ist

Natürlich werden Sie die Werte in der DB als NC_17 speichern müssen.

Das Problem ist, glaube ich, dass JPA nie mit der Idee im Kopf incepted war, dass wir ein komplexes bereits existierendes Schema bereits vorhanden haben könnten.

Ich denke, es gibt zwei Hauptmängel daraus resultierenden spezifischen zu Enum:

  1. Die Beschränkung der Verwendung name () und Ordnungs (). Warum nicht einfach einen Getter mit @Id markieren, die Art, wie wir mit @Entity tun?
  2. Enum die haben in der Regel Darstellung in der Datenbank zusammen mit allen Arten von Metadaten zu ermöglichen, einen Eigennamen, einschließlich einem beschreibenden Namen, vielleicht etwas mit Lokalisierung etc. Wir die einfache Bedienung eines Enum müssen mit der Flexibilität einer Entität kombiniert .

Hilfe meine Ursache und Abstimmung über JPA_SPEC-47

Was ist das

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

mit diesem verwenden Sie die Ratings als String sowohl auf dem DB und Einheit, sondern verwenden Sie die Enum für alles andere.

Mit dieser Anmerkung

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

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

}

vergleichen -> Enum

public class RatingComparator implementiert Vergleicher {

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

}

Gelöst !!! Wo ich die Antwort gefunden: http://programming.itags.org/development-tools/65254/

Kurz gesagt, sieht die Umwandlung für den Namen Enum, nicht den Wert des Attributs ‚Bewertung‘. In Ihrem Fall: Wenn Sie in den db-Werten "NC-17" haben, müssen Sie in Ihrem Enum haben:

Enum Bewertung {
(...)
NC-17 ( "NC-17");
(...)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top