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

时间:2010-09-03 20:03:46

标签: java hibernate orm jpa enums

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

7 个答案:

答案 0 :(得分:33)

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

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

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

答案 1 :(得分: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";
  }
}

对于实体,这里是代码:

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

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

答案 2 :(得分: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
}

也不起作用:

@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 :(得分:3)

据我所知,这是注释无法实现的:

  • 鉴别符值必须是String
  • 类型
  • discriminator值必须是编译时常量,即不允许来自枚举方法的返回值。

答案 4 :(得分:3)

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

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

其中DiscriminatorType只能是:

DiscriminatorType.STRING
DiscriminatorType.CHAR
DiscriminatorType.INTEGER
不幸的是,昨天我没有看到这个但很好。这是它的方式

答案 5 :(得分:2)

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

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

答案 6 :(得分:0)

我建议颠倒这种关系:将鉴别符值定义为实体中的常量,然后将其包装在枚举中:

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

除了消除重复之外,该代码还没有那么紧密地耦合:实体类不依赖于枚举值,可以添加而无需更改其他代码;而枚举可以“枚举”来自不同来源的不同类-取决于使用它的上下文。