使用SINGLE_TABLE继承策略时是否可以使用枚举作为鉴别器值?
答案 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
答案 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;
}
除了消除重复之外,该代码还没有那么紧密地耦合:实体类不依赖于枚举值,可以添加而无需更改其他代码;而枚举可以“枚举”来自不同来源的不同类-取决于使用它的上下文。