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

Bau*_*una 36 java orm enums hibernate jpa

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

Asa*_*Asa 35

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

@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";
    }   
}
Run Code Online (Sandbox Code Playgroud)

不是超级优雅,但比在多个地方保持价值要好.


Gen*_*enu 19

我只想改进@asa关于解决方法的最佳答案.通常,我们经常喜欢使用discriminator列作为抽象类的属性,并使用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";
  }
}
Run Code Online (Sandbox Code Playgroud)

对于实体,这里是代码:

@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 {
    …
}
Run Code Online (Sandbox Code Playgroud)

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


mar*_*ner 7

不,不幸的是你不能.

如果您尝试使用枚举作为鉴别器值,您将获得类型不匹配异常("无法从MyEnum转换为字符串"),因为唯一允许的鉴别器类型是String,Char和Integer.接下来,我尝试使用enum的名称和序号分别与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
}
Run Code Online (Sandbox Code Playgroud)

也不起作用:

@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
}
Run Code Online (Sandbox Code Playgroud)


Pas*_*ent 5

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

  • 鉴别器值必须是类型String
  • 鉴别器值必须是编译时常量,即不允许从枚举方法返回值。


小智 5

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

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

@Entity
@DiscriminatorValue(Square.DISCRIMINATOR_VALUE)
public class Square extends Shape {
    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;
}
Run Code Online (Sandbox Code Playgroud)

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