如何使用Hibernate/JPA将JAVA枚举映射到Postgresql枚举?

5
在我的Hibernate应用程序中,我想将Java枚举映射到Postgresql枚举,反之亦然。
我的应用程序使用apache-thrift、hibernate/JPA(用于ORM模型)和postgresql数据库。
Postgresql数据库使用命令定义了枚举。
CREATE TYPE status_enum AS ENUM ('UNDER-CONSTRUCTION', 'CLOSED', 'OPEN')

数据库初始有一些数据,其中部分元组的状态为“UNDER-CONSTRUCTION”。

以下是我的解决方案:

自定义类型用于枚举映射:

public class PsqlEnum extends EnumType {

    @Override
    public void nullSafeSet(final PreparedStatement st, final Object value, final int index,
            final SharedSessionContractImplementor session) throws SQLException {
        if(value == null) {
            st.setNull( index, Types.OTHER );
        }
        else {
            st.setObject(
                    index,
                    value.toString(),
                    Types.OTHER
            );
        }
    }
}

ORM(Hibernate)模型的实体:

@Entity
@Table(name = "place")
@TypeDef(
        name = "pgsql_enum",
        typeClass = PsqlEnum.class
)
public class Place implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id",nullable = false)
    @Getter @Setter private Integer id;

    @Column(name = "name")
    @Getter @Setter private String name;


    @Getter
    @Setter
    @Enumerated(EnumType.STRING)
    @Type(type = "pgsql_enum")
    @Column(name = "status_level",columnDefinition = "status_enum")
    private STATUS status;
}

枚举类:

public enum STATUS{
    CLOSED("CLOSED"),
    UNDERCONSTRUCTION("UNDER-CONSTRUCTION"),
    OPEN("OPEN");
    private final String label;
    Exposure(String label){
        this.label = label;
    }
    public String getLabel() {
        return label;
    }

    public static STATUS fromLabel(String label){
        for(STATUS currentEnum:STATUS.values()){
            if(currentEnum.getLabel().equals(label)){
                return currentEnum;
            }
        }
        return null;
    }

    @Override
    public String toString() {
        return this.label;
    }
}

在插入操作上运行很好,但在检索数据时出现错误:java.lang.IllegalArgumentException: Unknown name value [UNDER-CONSTRUCTION] for enum class

我尝试了StackOverflow中提供的每个参考解决方案,但没有一个能很好地解决我的问题。


如果可能的话,将psql枚举UNDER-CONSTRUCTION重命名为UNDERCONSTRUCTION,以匹配您在Java中定义的枚举。 - Lino
@Lino 这是其他人正在使用的实时数据库,所以我不能更改它。 - Badman
3个回答

0
所以我能够找出我缺少的东西。基本上,我必须在PsqlEnum.java文件中覆盖nullSafeGet和nullSafeSet两者。
我通过遵循这个java file达到了解决方案。
因此,无论是像链接中定义的自定义UserType还是自定义EnumType都可以工作。
在上面的代码PsqlEnum.java中,在自定义EnumType中,我忘记了覆盖nullSafeGet。

0
Hibernate在序列化枚举字段的值时使用Enumname()函数,而在反序列化实体时使用Enum.valueOf(...)函数。
这就是为什么你不能在枚举值中使用"UNDER-CONSTRUCTION"的原因。

0

这是可能的解决方案,您还需要在PsqlEnum类中重写nullSafeGet方法。

@Override
public Object nullSafeGet(ResultSet rs, String[] names,  SharedSessionContractImplementor session, Object owner) throws HibernateException, SQLException {
    String name = rs.getString(names[0]);
    if(rs.wasNull()) return  null;

    try {
        Field field = getClass().getSuperclass().getDeclaredField("enumClass");
        field.setAccessible(true);
        Class value = (Class) field.get(this);
        Optional<Object> object =  Arrays.stream(value.getEnumConstants()).filter(o -> o.toString().equals(name)).findFirst();
        return object.orElseThrow(() ->   new IllegalArgumentException(
            "No enum constant " + value + "." + name));
    } catch (ReflectiveOperationException e) {
        return super.nullSafeGet(rs, names, session, owner);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接