休眠PostgreSQL的枚举和Java枚举之间的映射 [英] Hibernate mapping between Postgresql enum and Java enum

查看:1040
本文介绍了休眠PostgreSQL的枚举和Java枚举之间的映射的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述


  • 春季3.x中,JPA 2.0,休眠4.x版和PostgreSQL 9.x中。

  • 在与我想要映射到一个PostgreSQL枚举枚举属性的Hibernate映射类的工作。

用,其中在ENUM列子句中抛出一个异常查询。

Querying with a where clause on the enum column throws an exception.

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.

code(重简体)

SQL:

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

CREATE TABLE move
(
    id serial NOT NULL PRIMARY KEY,
    directiontomove movedirection NOT NULL
);

Hibernate的映射类:

Hibernate mapped class:

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

Java的调用查询:

Java that calls the query:

public List<Move> getMoves(Direction directionToMove) {
    return (List<Direction>) sessionFactory.getCurrentSession()
            .getNamedQuery("getAllMoves")
            .setParameter("directionToMove", directionToMove)
            .list();
}

Hibernate的XML查询:

Hibernate xml query:

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

疑难解答


  • 通过查询 ID 而不是枚举按预期工作。

  • 无渣数据库的交互工作正常:

    Troubleshooting

    • Querying by id instead of the enum works as expected.
    • Java without database interaction works fine:

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


    • 的createQuery ,而不必在XML查询,类似的 findByRating 例如=HTTP ://tomee.apache.org/examples-trunk/jpa-enumerated/README.html相对=nofollow>通过@Enumerated文档Apache的JPA和枚举了同样的异常

    • 在PSQL查询与从移动选择*其中方向='左'; 按预期工作

    • 硬编码其中方向=前进在XML的查询。

    • .setParameter(方向,direction.name())不对,同样与 .setString() .setText(),异常变化:

    • createQuery instead of having the query in XML, similar to the findByRating example in Apache's JPA and Enums via @Enumerated documentation gave the same exception.
    • Querying in psql with select * from move where direction = 'LEFT'; works as expected.
    • Hardcoding where direction = 'FORWARD' in the query in the XML works.
    • .setParameter("direction", direction.name()) does not, same with .setString() and .setText(), exception changes to:

      Caused by: org.postgresql.util.PSQLException: ERROR: operator does not exist: movedirection = character varying
      



      • 自定义用户类型由该接受的答案的http:/ /stackoverflow.com/a/1594020/1090474 沿:

      @Column(name = "direction", nullable = false)
      @Enumerated(EnumType.STRING) // tried with and without this line
      @Type(type = "full.path.to.HibernateMoveDirectionUserType")
      private Direction directionToMove;
      


    • 与Hibernate的 EnumType 作为一个更高的额定但不能接​​受的答案的 http://stackoverflow.com/a/1604286/1090474 从同样的问题如上,连同:

    • Mapping with Hibernate's EnumType as suggested by a higher rated but not accepted answer http://stackoverflow.com/a/1604286/1090474 from the same question as above, along with:

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

      使用和不两个第二参数,眼看<后一href=\"http://stackoverflow.com/a/13241410/1090474\">http://stackoverflow.com/a/13241410/1090474

      With and without the two second parameters, after seeing http://stackoverflow.com/a/13241410/1090474

      一个JPA 2.1类型转换不应该是必要的,但不是一个选项不管,因为我在JPA 2.0现在。

      A JPA 2.1 Type Converter shouldn't be necessary, but isn't an option regardless, since I'm on JPA 2.0 for now.

      推荐答案

      别名正确使用的合格的属性名的是解决方案的第一部分。

      HQL

      Aliasing correctly and using the qualified property name was the first part of the solution.

      <query name="getAllMoves">
          <![CDATA[
              from Move as move
              where move.directionToMove = :direction
          ]]>
      </query>
      

      Hibernate映射

      @Enumerated(EnumType.STRING)仍然没有工作,所以自定义用户类型是必要的。关键是要正确地覆盖 nullSafeSet 像这个答案的http://计算器。 COM / A /1090474分之7614642并的从Web类似 实现

      Hibernate mapping

      @Enumerated(EnumType.STRING) still didn't work, so a custom UserType was necessary. The key was to correctly override nullSafeSet like in this answer http://stackoverflow.com/a/7614642/1090474 and similar implementations from the web.

      @Override
      public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException {
          if (value == null) {
              st.setNull(index, Types.VARCHAR);
          }
          else {
              st.setObject(index, ((Enum) value).name(), Types.OTHER);
          }
      }
      

      迂回

      实现ParameterizedType 没有合作:

      org.hibernate.MappingException: type is not parameterized: full.path.to.PGEnumUserType
      

      所以我没能注释枚举属性是这样的:

      so I wasn't able to annotate the enum property like this:

      @Type(type = "full.path.to.PGEnumUserType",
              parameters = {
                      @Parameter(name = "enumClass", value = "full.path.to.Move$Direction")
              }
      )
      

      相反,我声明的类,像这样:

      Instead, I declared the class like so:

      public class PGEnumUserType<E extends Enum<E>> implements UserType
      

      与构造:

      public PGEnumUserType(Class<E> enumClass) {
          this.enumClass = enumClass;
      }
      

      ,不幸的是,这意味着同样映射需要这样一个类中的任何其他枚举属性:

      which, unfortunately, means any other enum property similarly mapped will need a class like this:

      public class HibernateDirectionUserType extends PGEnumUserType<Direction> {
          public HibernateDirectionUserType() {
              super(Direction.class);
          }
      }
      

      注释

      注释财产,你就大功告成了。

      Annotation

      Annotate the property and you're done.

      @Column(name = "directiontomove", nullable = false)
      @Type(type = "full.path.to.HibernateDirectionUserType")
      private Direction directionToMove;
      

      其他笔记


      • EnhancedUserType 和三种方法会将需要实施

        Other notes

        • EnhancedUserType and the three methods it wants implemented

          public String objectToSQLString(Object value)
          public String toXMLString(Object value)
          public String objectToSQLString(Object value)
          

          并没有任何区别,我可以看到的,所以我坚持了实现用户类型

          这篇关于休眠PostgreSQL的枚举和Java枚举之间的映射的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆