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

发布于 2024-09-16 22:43:59 字数 43 浏览 4 评论 0原文

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

装纯掩盖桑 2024-09-23 22:43:59

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

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

实际上与 Hibernate/JPA 无关,但比必须在多个位置维护值要好。

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

Nothing to do with Hibernate/JPA really, but better than having to maintain the values in multiple places.

尽揽少女心 2024-09-23 22:43:59

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

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

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 enum of course. We can still use the solution mentioned above and force some consistencies between enum names (used to map the column) and String values (used as discrimnator values). Here is my suggestion:

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.

隔岸观火 2024-09-23 22:43:59

不,不幸的是你不能。

如果您尝试使用枚举作为鉴别器值,您将收到类型不匹配异常(“无法从 MyEnum 转换为字符串”),因为唯一允许的鉴别器类型是 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
}

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:

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
}
-柠檬树下少年和吉他 2024-09-23 22:43:59

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

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

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

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

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.

離殇 2024-09-23 22:43:59

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

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

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.
陌伤浅笑 2024-09-23 22:43:59

是的,当你定义鉴别器时,注释的选项是名称和鉴别器类型

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

,其中鉴别器类型只能是:

DiscriminatorType.STRING
DiscriminatorType.CHAR
DiscriminatorType.INTEGER

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

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

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

of which DiscriminatorType can only be:

DiscriminatorType.STRING
DiscriminatorType.CHAR
DiscriminatorType.INTEGER

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

若能看破又如何 2024-09-23 22:43:59

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

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

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

It must be 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文