【发布时间】:2015-03-04 10:32:40
【问题描述】:
背景
- 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
}
调用查询的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's JPA and Enums via @Enumerated documentation 中的findByRating示例给出了相同的异常。 - 在 psql 中使用
select * from move where direction = 'LEFT';查询可以正常工作。 - 在 XML 的查询中硬编码
where direction = 'FORWARD'。 -
.setParameter("direction", direction.name())没有,与.setString()和.setText()相同,异常更改为:Caused by: org.postgresql.util.PSQLException: ERROR: operator does not exist: movedirection = character varying
尝试解决问题
-
自定义
UserType由这个已接受的答案 https://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进行映射,由与上述相同问题的评分较高但未被接受的答案 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,它不那么脆弱,更灵活。
其他说明
JPA 2.1 类型转换器应该不是必需的,但无论如何都不是一个选项,因为我现在使用的是 JPA 2.0。
【问题讨论】:
-
这是一个写得很好的问题。我希望更多问题能够清楚地说明问题,显示相关代码并显示解决方法。干得好。
-
截至 2017 年 2 月 14 日,@cslotty 的链接已失效。
标签: java postgresql enums annotations hibernate-mapping