Стратегия наследования SINGLE_TABLE с использованием перечислений в качестве значения дискриминатора - PullRequest
35 голосов
/ 04 сентября 2010

Можно ли использовать перечисление в качестве значения дискриминатора при использовании стратегии наследования SINGLE_TABLE?

Ответы [ 7 ]

33 голосов
/ 24 апреля 2013

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

@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="FREQUENCY",
    discriminatorType=DiscriminatorType.STRING
)    
public abstract class Event  {
}

@Entity
@DiscriminatorValue(value=Frequency.Values.WEEKLY)
public class WeeklyEvent extends Event {
    …
}

public enum Frequency {
    DAILY(Values.DAILY),
    WEEKLY(Values.WEEKLY),
    MONTHLY(Values.MONTHLY);

    private String value;

    …

    public static class Values {
        public static final String DAILY = "D";
        public static final String WEEKLY = "W";
        public static final String MONTHLY = "M";
    }   
}

Не супер элегантно, но лучше, чем поддерживать значения в нескольких местах.

19 голосов
/ 03 ноября 2014

Я просто хотел улучшить отличный ответ @asa об обходном пути.Обычно нам часто нравится использовать столбец дискриминатора в качестве атрибута абстрактного класса, и, конечно, он отображается с enum.Мы все еще можем использовать решение, упомянутое выше, и установить некоторую согласованность между enum именами (используемыми для сопоставления столбца) и String значениями (используемыми в качестве значений дискриминатора).Вот мое предложение:

public enum ELanguage {
  JAVA(Values.JAVA), GROOVY(Values.GROOVY);

  private ELanguage (String val) {
     // force equality between name of enum instance, and value of constant
     if (!this.name().equals(val))
        throw new IllegalArgumentException("Incorrect use of ELanguage");
  }

  public static class Values {
     public static final String JAVA= "JAVA";
     public static final String GROOVY= "GROOVY";
  }
}

А для сущностей вот код:

@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="LANGUAGE_TYPE", discriminatorType=DiscriminatorType.STRING)    
public abstract class Snippet {
   // update/insert is managed by discriminator mechanics
   @Column(name = "LANGUAGE_TYPE", nullable = false, insertable = false, updatable = false) 
   @Enumerated(EnumType.STRING)
   public ELanguage languageType
}

@Entity
@DiscriminatorValue(value=ELanguage.Values.JAVA)
public class JavaSnippet extends Snippet {
    …
}

Все еще не идеально, но, думаю, немного лучше.

7 голосов
/ 17 октября 2012

Нет, к сожалению, вы не можете.

Если вы попытаетесь использовать перечисление в качестве значения дискриминатора, вы получите исключение несоответствия типов («не удается преобразовать из MyEnum в String»), поскольку единственными допустимыми типами дискриминатора являются String, Char и Integer.Затем я попытался использовать имя и порядковый номер перечисления в сочетании с DiscriminatorType.STRING и DiscriminatorType.INTEGER, соответственно.Но это тоже не сработало, так как аннотация @DiscriminatorValue (как и любая другая) требует константного выражения:

Это не работает:

@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="FREQUENCY",
    discriminatorType=DiscriminatorType.STRING
)    
public abstract class Event  {}

@Entity
@DiscriminatorValue(value=Frequency.WEEKLY.name())
public class WeeklyEvent extends Event {
    // Exception: The value for annotation attribute DiscriminatorValue.value must be a constant expression
}

Также не работает:

@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="FREQUENCY",
    discriminatorType=DiscriminatorType.INTEGER
) 
public abstract class Event  {}

@Entity
@DiscriminatorValue(value=Frequency.WEEKLY.ordinal())
public class WeeklyEvent extends Event {
    // Exception: The value for annotation attribute DiscriminatorValue.value must be a constant expression
}
3 голосов
/ 31 мая 2012

да, когда вы определяете дискриминатор, опцией аннотации являются имя иcrimatorType

@DiscriminatorColumn (name="MYDISCRIMINATOR", discriminatorType= DiscriminatorType.INTEGER)

из которых DiscriminatorType может быть только:

DiscriminatorType.STRING
DiscriminatorType.CHAR
DiscriminatorType.INTEGER

прискорбно, я не видел этого вчера, ноЧто ж.Так оно и есть

3 голосов
/ 04 сентября 2010

Насколько мне известно, это невозможно с аннотациями:

  • значение дискриминатора должно быть типа String
  • значение дискриминатора должно быть постоянной времени компиляции, то есть возвращаемые значения из методов в перечислениях не допускаются.
2 голосов
/ 27 марта 2013

Вы можете использовать DiscriminatorType.INTEGER и сопоставить каждый подкласс с @DiscriminatorValue("X"), где X должно быть порядковым значением перечисления (0,1,2,3 ...).

Это должно быть значением как константа String .Вы не можете использовать YourEnum.SOME_VALUE.ordinal(), потому что значения атрибута аннотации должны быть константами.Да, это утомительно.Да, это подвержено ошибкам.Но это работает.

0 голосов
/ 21 июня 2019

Я бы предложил инвертировать отношение: определите значение дискриминатора как константу в сущности, затем оберните его в перечисление:

@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(
        name = "FIELD_TYPE",
        discriminatorType = DiscriminatorType.STRING
)
public class Shape {
}

@Entity
@DiscriminatorValue(Square.DISCRIMINATOR_VALUE)
public class Square extends Parent  {

    public static final String DISCRIMINATOR_VALUE = "SQUARE";
}

@Entity
@DiscriminatorValue(Circle.DISCRIMINATOR_VALUE)
public class Circle extends Shape {

    public static final String DISCRIMINATOR_VALUE = "CIRCLE";
}

@AllArgsConstructor
public enum FieldType {
    SHAPE(Shape.DISCRIMINATOR_VALUE),
    CIRCLE(Circle.DISCRIMINATOR_VALUE);

    @Getter
    private final String discriminatorValue;
}

Помимо устранения дублирования, этот код также менее тесно связан: классы сущностей не зависят от значений перечисления и могут быть добавлены без необходимости изменения другого кода; в то время как enum может «перечислять» разные классы из разных источников - в зависимости от контекста, в котором он используется.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...