【问题标题】:Force the usage of a JPA AttributeConverter for enums强制对枚举使用 JPA AttributeConverter
【发布时间】:2014-07-31 05:58:12
【问题描述】:

我们正在尝试找出一种使用 JPA 持久化枚举的稳健方法。使用@Enumerated 的常用方法是不可取的,因为重构时很容易破坏映射。每个枚举都应该有一个单独的数据库值,该值可以不同于枚举名称/顺序,以便您可以安全地更改枚举的名称或内部顺序(例如序数值)而不会破坏任何内容。例如。 this blog post 有一个关于如何实现这一点的示例,但我们觉得建议的解决方案给代码增加了太多混乱。我们希望通过使用 JPA 2.1 中引入的新 AttributeConverter 机制来实现类似的结果。我们有一个每个枚举都应该实现的接口,该接口定义了一个获取用于将枚举存储在数据库中的值的方法。示例:

public interface PersistableEnum {
    String getDatabaseValue();
}

...

public enum SomeEnum implements PersistableEnum {
    FOO("foo"), BAR("bar");

    private String databaseValue;

    private SomeEnum(String databaseValue) {
        this.databaseValue = databaseValue;
    }

    public void getDatabaseValue() {
        return databaseValue;
    }
}

我们还有一个基本转换器,它具有将枚举转换为字符串的逻辑,反之亦然,并为每种枚举类型单独的具体转换器类(AFAIK,不可能实现完全通用的枚举转换器,这也注意到@ 987654322@)。然后,具体的转换器只需调用进行转换的基类,如下所示:

public abstract class EnumConverter<E extends PersistableEnum> {

    protected String toDatabaseValue(E value) {
        // Do the conversion...
    }

    protected E toEntityAttribute(Class<E> enumClass, String value) {
        // Do the conversion...
    }
}

...

@Converter(autoApply = true)
public class SomeEnumConverter extends EnumConverter<SomeEnum> 
            implements AttributeConverter<SomeEnum, String> {

    public String convertToDatabaseColumn(SomeEnum attribute) {
        return toDatabaseValue(attribute);
    }

    public SomeEnum convertToEntityAttribute(String dbData) {
        return toEntityAttribute(SomeEnum.class, dbData);
    }
}

然而,虽然这种方法在技术意义上非常有效,但仍然存在一个非常严重的缺陷:每当有人创建一个新的枚举类,其值需要存储到数据库中时,该人还需要记住创建新的枚举类enum 实现PersistableEnum 接口并为其编写转换器类。没有这个,枚举将毫无问题地持久化,但转换将默认使用@Enumerated(EnumType.ORDINAL),这正是我们想要避免的。我们怎样才能防止这种情况发生?有没有办法让 JPA(在我们的例子中是 Hibernate)不默认为任何映射,但是例如如果没有在字段上定义 @Enumerated 并且找不到该类型的转换器,则抛出异常?或者我们可以创建一个“包罗万象”的转换器,为所有没有自己特定转换器类的枚举调用,并且总是从那里抛出异常?还是我们只能忍气吞声,每次都尝试记住额外的步骤?

【问题讨论】:

标签: java hibernate jpa enums


【解决方案1】:

您要确保所有 枚举 都是 PersistableEnum 的实例。

您需要设置一个默认实体监听器(一个实体监听器,其回调适用于持久性单元中的所有实体)。

Default Entity Listener 类中实现 @PrePersist 方法并确保所有 Enums 都是 PersistableEnum 的实例。

【讨论】:

    猜你喜欢
    • 2020-02-29
    • 1970-01-01
    • 2013-01-15
    • 2019-10-09
    • 1970-01-01
    • 1970-01-01
    • 2012-08-22
    • 2016-11-10
    • 2012-09-16
    相关资源
    最近更新 更多