出身背景
- 春天3.x、 JPA 2.0,Hibernate 4.x、 Postgresql 9.十、
- 正在处理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
);
Hibernate映射类:
@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();
}
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; }
-
createQuery
没有使用XML进行查询,类似于Apache's JPA and Enums via @Enumerated documentation中的findByRating
示例给出了相同的异常. - 在psql中查询
select * from move where direction = 'LEFT';
项工作正常. - Hardcoding 100 in the query in the XML works.
-
与
.setString()
和.setText()
相同,.setParameter("direction", direction.name())
不会将异常更改为: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的
EnumType
进行映射,如上面同一个问题中评分较高但未被接受的答案https://stackoverflow.com/a/1604286/1090474所示,以及:@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后
- 试着在答案https://stackoverflow.com/a/20252215/1090474中注释getter和setter.
- 我没有试过
EnumType.ORDINAL
,因为我想坚持EnumType.STRING
,它不那么脆弱,也更灵活.
其他注释
JPA2.1类型转换器应该不是必需的,但无论如何都不是一个选项,因为我现在正在使用JPA2.0.