java SINGLE_TABLE 使用枚举作为鉴别器值的继承策略

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3639225/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 02:47:06  来源:igfitidea点击:

SINGLE_TABLE inheritance strategy using enums as discriminator value

javahibernateormjpaenums

提问by Bauna

Is it possible to use an enum as a discriminator value when using SINGLE_TABLE inheritance strategy?

使用 SINGLE_TABLE 继承策略时是否可以使用枚举作为鉴别器值?

回答by Asa

If what you are trying to achieve is to not to duplicate the discriminator values, there is a simple workaround.

如果您要实现的是不复制鉴别器值,则有一个简单的解决方法。

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

Not super elegant, but better than having to maintain the values in multiple places.

不是超级优雅,但比必须在多个地方维护值要好。

回答by Genu

I just wanted to improve the great answer of @asa about the workaround. Usually, we often like to use the discriminator column as an attribute of the abstract class, and mapped with an enumof course. We can still use the solution mentioned above and force some consistencies between enumnames (used to map the column) and Stringvalues (used as discrimnator values). Here is my suggestion:

我只是想改进@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";
  }
}

And for the entities, here is the code:

对于实体,这里是代码:

@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 {
    …
}

Still not perfect, but a little bit better, I think.

仍然不完美,但我认为更好一点。

回答by marciowerner

No, unfortunately you can't.

不,不幸的是你不能。

If you try to use an enum as discriminator value, you'll get a Type Mismatch exception ("cannot convert from MyEnum to String"), as the only discriminator types allowed are String, Char and Integer. Next, I tried using an enum's name and ordinal combined with DiscriminatorType.STRING and DiscriminatorType.INTEGER, respectively. But this didn't work either, as the @DiscriminatorValue annotation (as any other) requires a constant expression:

如果您尝试使用枚举作为鉴别器值,则会出现类型不匹配异常(“无法从 MyEnum 转换为字符串”),因为唯一允许的鉴别器类型是 String、Char 和 Integer。接下来,我尝试将枚举的名称和序号分别与 DiscriminatorType.STRING 和 DiscriminatorType.INTEGER 结合使用。但这也不起作用,因为 @DiscriminatorValue 注释(和其他注释一样)需要一个常量表达式:

This doesn't work:

这不起作用:

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

Doesn't work either:

也不起作用:

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

回答by Pascal Thivent

To my knowledge, this is not possible with annotations:

据我所知,这是不可能的注释:

  • discriminator value must be of type String
  • discriminator value must be a compile-time-constant, i.e. return values from methods on enums are not allowed.
  • 鉴别器值必须是类型 String
  • 鉴别器值必须是编译时常量,即不允许从枚举方法的返回值。

回答by Luis Ramirez-Monterosa

yup ,when you define discriminator the annotation's option are name and discrimatorType

是的,当您定义鉴别器时,注释的选项是 name 和 discrimatorType

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

of which DiscriminatorType can only be:

其中 DiscriminatorType 只能是:

DiscriminatorType.STRING
DiscriminatorType.CHAR
DiscriminatorType.INTEGER

unfortunate I didn't see this yesterday but well. That's the way it is

不幸的是我昨天没有看到这个但是很好。它就是这样儿的

回答by Albert Gevorgyan

I would suggest to invert the relationship: define the discriminator value as a constant in the entity, then wrap it in the enum:

我建议反转关系:将鉴别器值定义为实体中的常量,然后将其包装在枚举中:

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

Apart from eliminating duplication, this code is also less tightly coupled: entity classes don't depend on enum values and can be added without having to change other code; while the enum can "enumerate" different classes from different sources - depending on the context where it is used.

除了消除重复之外,这段代码的耦合度也较低:实体类不依赖于枚举值,无需更改其他代码即可添加;而枚举可以“枚举”来自不同来源的不同类 - 取决于使用它的上下文。

回答by tetsuo

You can use DiscriminatorType.INTEGER, and map each subclass with @DiscriminatorValue("X"), where Xmust be the ordinal value of the enum (0,1,2,3...).

您可以使用DiscriminatorType.INTEGER, 并用 映射每个子类@DiscriminatorValue("X"),其中X必须是枚举的序数值 (0,1,2,3...)。

It mustbe the value as a constant String. You can't use YourEnum.SOME_VALUE.ordinal(), because annotation attribute values must be constants. Yes, it is tedious. Yes, it is error-prone. But it works.

必须作为常量 String的值。您不能使用YourEnum.SOME_VALUE.ordinal(),因为注释属性值必须是常量。是的,这很乏味。是的,它很容易出错。但它有效。