Background
- Spring 3.x, JPA 2.0, Hibernate 4.x, Postgresql 9.x.
- Working on a Hibernate mapped class with an enum property that I want to map to a Postgresql enum.
Problem
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 (heavily simplified)
SQL:
create type movedirection as enum (
'FORWARD', 'LEFT'
);
CREATE TABLE move
(
id serial NOT NULL PRIMARY KEY,
directiontomove movedirection NOT NULL
);
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 that calls the query:
public List<Move> getMoves(Direction directionToMove) {
return (List<Direction>) sessionFactory.getCurrentSession()
.getNamedQuery("getAllMoves")
.setParameter("directionToMove", directionToMove)
.list();
}
Hibernate xml query:
<query name="getAllMoves">
<![CDATA[
select move from Move move
where directiontomove = :directionToMove
]]>
</query>
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
instead of having the query in XML, similar to thefindByRating
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
Attempts at resolution
Custom
UserType
as suggested by this accepted answer https://mcmap.net/q/356582/-hibernate-enum-mapping along with:@Column(name = "direction", nullable = false) @Enumerated(EnumType.STRING) // tried with and without this line @Type(type = "full.path.to.HibernateMoveDirectionUserType") private Direction directionToMove;
Mapping with Hibernate's
EnumType
as suggested by a higher rated but not accepted answer https://mcmap.net/q/356582/-hibernate-enum-mapping 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") })
With and without the two second parameters, after seeing https://mcmap.net/q/356583/-hibernate-enumtype-instantiation-exception
- Tried annotating the getter and setter like in this answer https://mcmap.net/q/356584/-hibernate-query-using-enum-as-parameter.
- Haven't tried
EnumType.ORDINAL
because I want to stick withEnumType.STRING
, which is less brittle and more flexible.
Other notes
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.
package-info.java
. – Horney