当前位置: 首页 > 知识库问答 >
问题:

PostgreSQL枚举和Java枚举之间的Hibernate映射

狄玮
2023-03-14
  • Spring 3.x、JPA 2.0、Hibernate 4.x、Postgresql 9.x.
  • 使用希望映射到Postgresql枚举的枚举属性处理Hibernate映射类。

使用枚举列上的where子句进行查询会引发异常。

org.hibernate.exception.SQLGrammarException: could not extract ResultSet
... 
Caused by: org.postgresql.util.PSQLException: ERROR: operator does not exist: movedirection = bytea
  Hint: No operator matches the given name and argument type(s). You might need to add explicit type casts.

SQL:

create type movedirection as enum (
    'FORWARD', 'LEFT'
);

CREATE TABLE move
(
    id serial NOT NULL PRIMARY KEY,
    directiontomove movedirection NOT NULL
);
@Entity
@Table(name = "move")
public class Move {

    public enum Direction {
        FORWARD, LEFT;
    }

    @Id
    @Column(name = "id")
    @GeneratedValue(generator = "sequenceGenerator", strategy=GenerationType.SEQUENCE)
    @SequenceGenerator(name = "sequenceGenerator", sequenceName = "move_id_seq")
    private long id;

    @Column(name = "directiontomove", nullable = false)
    @Enumerated(EnumType.STRING)
    private Direction directionToMove;
    ...
    // getters and setters
}
public List<Move> getMoves(Direction directionToMove) {
    return (List<Direction>) sessionFactory.getCurrentSession()
            .getNamedQuery("getAllMoves")
            .setParameter("directionToMove", directionToMove)
            .list();
}

Hibernate xml查询:

<query name="getAllMoves">
    <![CDATA[
        select move from Move move
        where directiontomove = :directionToMove
    ]]>
</query>

>

  • ID而不是按枚举查询工作正常。
  • 没有数据库交互的Java工作良好:

    public List<Move> getMoves(Direction directionToMove) {
        List<Move> moves = new ArrayList<>();
        Move move1 = new Move();
        move1.setDirection(directionToMove);
        moves.add(move1);
        return moves;
    }
    

    .setParameter(“direction”,direction.name())不是,与.setString().setText()相同,异常更改为:

    Caused by: org.postgresql.util.PSQLException: ERROR: operator does not exist: movedirection = character varying
    
    @Column(name = "direction", nullable = false)
    @Enumerated(EnumType.STRING) // tried with and without this line
    @Type(type = "full.path.to.HibernateMoveDirectionUserType")
    private Direction directionToMove;
    
    @Type(type = "org.hibernate.type.EnumType",
        parameters = {
                @Parameter(name  = "enumClass", value = "full.path.to.Move$Direction"),
                @Parameter(name = "type", value = "12"),
                @Parameter(name = "useNamed", value = "true")
        })
    

    在查看https://stackoverflow.com/A/13241410/1090474之后,可以使用和不使用第二个参数

    JPA2.1类型的转换器不应该是必需的,但无论如何也不是一个选项,因为我现在正在使用JPA2.0。

  • 共有1个答案

    靳涵亮
    2023-03-14

    您可以通过Maven Central使用Hibernate类型依赖关系获得这些类型:

    <dependency>
        <groupId>com.vladmihalcea</groupId>
        <artifactId>hibernate-types-52</artifactId>
        <version>${hibernate-types.version}</version>
    </dependency>
    

    如果使用以下自定义类型轻松地将Java枚举映射到PostgreSQL枚举列类型:

    public class PostgreSQLEnumType extends org.hibernate.type.EnumType {
         
        public void nullSafeSet(
                PreparedStatement st, 
                Object value, 
                int index, 
                SharedSessionContractImplementor session) 
            throws HibernateException, SQLException {
            if(value == null) {
                st.setNull( index, Types.OTHER );
            }
            else {
                st.setObject( 
                    index, 
                    value.toString(), 
                    Types.OTHER 
                );
            }
        }
    }
    

    要使用它,您需要使用Hibernate@type注释对字段进行注释,如下例所示:

    @Entity(name = "Post")
    @Table(name = "post")
    @TypeDef(
        name = "pgsql_enum",
        typeClass = PostgreSQLEnumType.class
    )
    public static class Post {
     
        @Id
        private Long id;
     
        private String title;
     
        @Enumerated(EnumType.STRING)
        @Column(columnDefinition = "post_status_info")
        @Type( type = "pgsql_enum" )
        private PostStatus status;
     
        //Getters and setters omitted for brevity
    }
    
    CREATE TYPE post_status_info AS ENUM (
        'PENDING', 
        'APPROVED', 
        'SPAM'
    )
    
     类似资料:
    • 问题内容: 背景 Spring 3.x,JPA 2.0,Hibernate 4.x,Postgresql 9.x. 使用我想映射到Postgresql枚举的enum属性在Hibernate映射的类上工作。 问题 用enum列上的where子句查询会引发异常。 代码(大大简化) SQL: Hibernate映射类: 调用查询的Java: Hibernate xml查询: 故障排除 按查询而不是枚举按

    • 问题内容: Enumeration <有区别吗?扩展ZipEntry>和Enumeration ?如果是这样,有什么区别? 问题答案: 拥有其中一种后,您在做什么上没有实际差异,因为type参数仅在“输出”位置使用。另一方面,在您可以 用作 其中一个的方面有很大的不同。 假设您有一个-您无法将其传递给作为其参数之一的方法。您 可以 将其传递给采用方法。 当您有一个在输入和输出位置都使用type参数

    • 问题内容: 枚举具有获取枚举常量的方法,并且在具有 我发现的名称的类中存在的相同类型的方法都给出相同的输出。那还有什么其他区别。如果没有区别,那么为什么要添加JSL ? 问题答案: 包括该方法的原因是它可以与任何方法一起使用。相比之下, 用于特定方法的方法仅适用于该特定方法…,因为类不能被多态使用。 显然,该方法仅在您实现 需要 针对多种类型使用的代码的情况下才真正有用……而泛型则不会削减它。

    • 问题内容: 我需要预先将未实现接口的枚举映射到现有数据库,该数据库使用将该枚举存储在与所有者类相同的表中。 在这种情况下应如何处理映射?持久化到数据库不会改变,因为实现该接口的所有枚举都将具有不同的值,但是我不确定应如何从数据库中检索对象(我是否需要自定义映射器,它将尝试实例化一个使用指定的enum类进行枚举吗?Hibernate本身是否支持此功能?)。 问题答案: 可以创建一个自定义(例如thi

    • 问题内容: Hibernate提供的注释支持使用或的两种类型的映射。当我们使用映射时,它使用的“名称” 而不是Enum的表示形式。在数据库列仅包含一个字符的情况下,这是一个问题。例如,我有以下枚举: 当我坚持枚举使用,即hibernate尝试在数据库中存储的值是开放的。但是,我的数据库列仅包含一个字符,因此会引发异常。 克服这个问题的一个办法是改变枚举类型持有单个字符(如,代替,)。但是,这降低了

    • 谁能解释一下 和 我经常使用前一个示例(可能太频繁了,没有足够的封装),但我从未使用过第二个示例。 谢啦 枚举