PostgreSQL enum 和 Java enum 之间的 Hibernate 映射
背景
- Spring 3.x, JPA 2.0, Hibernate 4.x, Postgresql 9.x.
- 使用一个包含枚举属性的Hibernate映射类,我想将其映射到Postgresql枚举。
问题
使用枚举列上的 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
}
调用查询的 Java:
public List<Move> getMoves(Direction directionToMove) {
return (List<Direction>) sessionFactory.getCurrentSession()
.getNamedQuery("getAllMoves")
.setParameter("directionToMove", directionToMove)
.list();
}
休眠 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; }
-
createQuery
而不是在XML中进行查询,类似于Apache的JPA和Enums中的示例,@Enumerated文档给出了相同的异常。findByRating
- 在 psql 中使用查询按预期工作。
select * from move where direction = 'LEFT';
- 在 XML 中的查询中
,方向 = 'FORWARD'
的硬编码工作正常。 -
.setParameter("direction", direction.name())
不,与 和 相同,异常更改为:.setString()
.setText()
Caused by: org.postgresql.util.PSQLException: ERROR: operator does not exist: movedirection = character varying
尝试解决问题
-
此接受的答案建议的自定义 https://stackoverflow.com/a/1594020/1090474 以及:
UserType
@Column(name = "direction", nullable = false) @Enumerated(EnumType.STRING) // tried with and without this line @Type(type = "full.path.to.HibernateMoveDirectionUserType") private Direction directionToMove;
-
与Hibernate的映射,如更高评级但未被接受的答案所建议的那样,来自与上述相同的问题 https://stackoverflow.com/a/1604286/1090474,以及:
EnumType
@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
- 尝试像这个答案中那样注释 getter 和 setter https://stackoverflow.com/a/20252215/1090474。
- 没有尝试过,因为我想坚持,它不那么脆弱,更灵活。
EnumType.ORDINAL
EnumType.STRING
其他注意事项
JPA 2.1 类型转换器不应该是必需的,但无论如何都不是一个选项,因为我现在使用的是 JPA 2.0。