Вопрос

У меня есть существующая база данных системы проката фильмов.У каждого фильма есть атрибут рейтинга.В 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() направление enum -> String работает нормально, но String -> enum не работает.Я получаю следующее исключение:

[Предупреждение TopLink]:2008.12.09 01: 30: 57.434-Серверсессия (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 [Rating-> Film.Rating] дескриптор:Relationaldescriptor (de.fhw.nsdb.entitiets.film -> [Databaseable (Film)]))

ваше здоровье

Тимо

Это было полезно?

Решение

Похоже, вам нужно добавить поддержку пользовательского типа:

Расширение OracleAS TopLink для поддержки пользовательских преобразований типов

Другие советы

Вы пытались сохранить порядковое значение.Сохранение строкового значения работает нормально, если у вас нет связанной со значением строки:

@Enumerated(EnumType.ORDINAL)

Здесь у вас есть проблема: ограниченные возможности JPA при обработке перечислений.С перечислениями у вас есть два варианта:

  1. Сохраните их как число, равное Enum.ordinal(), это ужасная идея (имхо);или
  2. Сохраните их как строку, равную Enum.name(). Примечание: нет toString() как и следовало ожидать, тем более, что поведение по умолчанию для Enum.toString() это вернуться name().

Лично я считаю, что лучший вариант — (2).

Теперь у вас есть проблема в том, что вы определяете значения, которые не представляют допустимые имена экземпляров в Java (а именно, с использованием дефиса).Итак, ваш выбор:

  • Измените свои данные;
  • Сохранять строковые поля и неявно преобразовывать их в перечисления или из них в ваших объектах;или
  • Используйте нестандартные расширения, такие как TypeConverters.

Я бы сделал их именно в таком порядке (от первого до последнего) в порядке предпочтения.

Кто-то предложил конвертер Oracle TopLink, но вы, вероятно, используете Toplink Essentials, являющийся эталонной реализацией JPA 1.0, которая является подмножеством коммерческого продукта Oracle Toplink.

В качестве еще одного предложения я настоятельно рекомендую перейти на ЗатмениеСсылка.Это гораздо более полная реализация, чем Toplink Essentials, и Eclipselink станет эталонной реализацией JPA 2.0 после выпуска (ожидается JavaOne в середине следующего года).

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.

я не знаю внутреннего устройства 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.

Проблема, я думаю, в том, что JPA никогда не создавался с мыслью о том, что у нас может быть уже существующая сложная схема.

Я думаю, что из этого вытекают два основных недостатка, характерных для Enum:

  1. Ограничение использования name() и ordinal().Почему бы просто не пометить получатель @Id, как мы это делаем с @Entity?
  2. Перечисления обычно представлены в базе данных, чтобы обеспечить связь со всеми видами метаданных, включая имя собственное, описательное имя, возможно, что-то с локализацией и т. д.Нам нужна простота использования Enum в сочетании с гибкостью Entity.

Помогите моему делу и проголосуйте за JPA_SPEC-47

Как насчет этого

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

при этом вы используете рейтинги как строку как в своей БД, так и в объекте, но используете перечисление для всего остального.

используйте эту аннотацию

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

}

сравнить -> Перечислить

публичный класс RatingComparator реализует Comparator {

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

}

Решено!!!Где я нашел ответ: http://programming.itags.org/development-tools/65254/

Вкратце, преобразование ищет имя перечисления, а не значение атрибута «рейтинг».В твоем случае:Если у вас есть значения в базе данных «NC-17», вам необходимо иметь в своем перечислении:

перечисление Рейтинг {
(...)
НК-17 ("НК-17");
(...)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top