Ken*_*sky 25 java postgresql enums annotations hibernate-mapping
查询枚举列上的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.
Run Code Online (Sandbox Code Playgroud)
SQL:
create type movedirection as enum (
'FORWARD', 'LEFT'
);
CREATE TABLE move
(
id serial NOT NULL PRIMARY KEY,
directiontomove movedirection NOT NULL
);
Run Code Online (Sandbox Code Playgroud)
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
}
Run Code Online (Sandbox Code Playgroud)
调用查询的Java:
public List<Move> getMoves(Direction directionToMove) {
return (List<Direction>) sessionFactory.getCurrentSession()
.getNamedQuery("getAllMoves")
.setParameter("directionToMove", directionToMove)
.list();
}
Run Code Online (Sandbox Code Playgroud)
Hibernate xml查询:
<query name="getAllMoves">
<![CDATA[
select move from Move move
where directiontomove = :directionToMove
]]>
</query>
Run Code Online (Sandbox Code Playgroud)
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;
}
Run Code Online (Sandbox Code Playgroud)createQuery而不是使用XML进行查询,类似于Apache的JPA和Enums中的findByRating示例,通过@Enumerated文档给出了相同的异常.select * from move where direction = 'LEFT';预期的工作查询psql .where direction = 'FORWARD'中的查询中的硬编码有效..setParameter("direction", direction.name())不,同样与.setString()和.setText(),异常的变化:
Caused by: org.postgresql.util.PSQLException: ERROR: operator does not exist: movedirection = character varying
Run Code Online (Sandbox Code Playgroud)UserType按照此接受的答案建议自定义/sf/answers/111581431/以及:
@Column(name = "direction", nullable = false)
@Enumerated(EnumType.STRING) // tried with and without this line
@Type(type = "full.path.to.HibernateMoveDirectionUserType")
private Direction directionToMove;
Run Code Online (Sandbox Code Playgroud)如上所述,EnumType通过更高评级但未被接受的答案/sf/answers/112300051/建议使用Hibernate映射,以及:
@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")
})
Run Code Online (Sandbox Code Playgroud)
在看到/sf/answers/926898731/之后,有和没有两个第二个参数
EnumType.ORDINAL因为我想坚持EnumType.STRING,这不那么脆弱,更灵活.JPA 2.1类型转换器不是必需的,但不管怎样都不是,因为我现在正在使用JPA 2.0.
Vla*_*cea 33
您不必手动创建以下所有Hibernate类型.您可以使用以下依赖项通过Maven Central获取它们:
<dependency>
<groupId>com.vladmihalcea</groupId>
<artifactId>hibernate-types-52</artifactId>
<version>${hibernate-types.version}</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)
有关更多信息,请查看hibernate类型的开源项目.
正如我在本文中所解释的,如果您使用以下自定义类型轻松地将Java Enum映射到PostgreSQL Enum列类型:
public class PostgreSQLEnumType extends org.hibernate.type.EnumType {
public void nullSafeSet(
PreparedStatement st,
Object value,
int index,
SharedSessionContractImplementor session)
throws HibernateException, SQLException {
if(value == null) {
st.setNull( index, Types.OTHER );
}
else {
st.setObject(
index,
value.toString(),
Types.OTHER
);
}
}
}
Run Code Online (Sandbox Code Playgroud)
要使用它,您需要使用Hibernate @Type注释来注释该字段,如以下示例所示:
@Entity(name = "Post")
@Table(name = "post")
@TypeDef(
name = "pgsql_enum",
typeClass = PostgreSQLEnumType.class
)
public static class Post {
@Id
private Long id;
private String title;
@Enumerated(EnumType.STRING)
@Column(columnDefinition = "post_status_info")
@Type( type = "pgsql_enum" )
private PostStatus status;
//Getters and setters omitted for brevity
}
Run Code Online (Sandbox Code Playgroud)
此映射假定您post_status_info在PostgreSQL中具有枚举类型:
CREATE TYPE post_status_info AS ENUM (
'PENDING',
'APPROVED',
'SPAM'
)
Run Code Online (Sandbox Code Playgroud)
就是这样,它就像一个魅力.这是对GitHub的测试证明了这一点.
正确别名并使用限定属性名称是解决方案的第一部分.
<query name="getAllMoves">
<![CDATA[
from Move as move
where move.directionToMove = :direction
]]>
</query>
Run Code Online (Sandbox Code Playgroud)
@Enumerated(EnumType.STRING)仍然没有工作,所以一个习惯UserType是必要的.关键是要正确覆盖,nullSafeSet如在这个答案/sf/answers/533024971/和网络上的类似 实现.
@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);
}
}
Run Code Online (Sandbox Code Playgroud)
implements ParameterizedType 没合作:
org.hibernate.MappingException: type is not parameterized: full.path.to.PGEnumUserType
Run Code Online (Sandbox Code Playgroud)
所以我无法像这样注释枚举属性:
@Type(type = "full.path.to.PGEnumUserType",
parameters = {
@Parameter(name = "enumClass", value = "full.path.to.Move$Direction")
}
)
Run Code Online (Sandbox Code Playgroud)
相反,我宣布这样的类是这样的:
public class PGEnumUserType<E extends Enum<E>> implements UserType
Run Code Online (Sandbox Code Playgroud)
使用构造函数:
public PGEnumUserType(Class<E> enumClass) {
this.enumClass = enumClass;
}
Run Code Online (Sandbox Code Playgroud)
遗憾的是,这意味着任何其他类似映射的枚举属性都需要这样的类:
public class HibernateDirectionUserType extends PGEnumUserType<Direction> {
public HibernateDirectionUserType() {
super(Direction.class);
}
}
Run Code Online (Sandbox Code Playgroud)
注释财产,你就完成了.
@Column(name = "directiontomove", nullable = false)
@Type(type = "full.path.to.HibernateDirectionUserType")
private Direction directionToMove;
Run Code Online (Sandbox Code Playgroud)
EnhancedUserType 以及它想要实施的三种方法
public String objectToSQLString(Object value)
public String toXMLString(Object value)
public String objectToSQLString(Object value)
Run Code Online (Sandbox Code Playgroud)
我没看到任何差别,所以我坚持了下来implements UserType.
nullSafeGet两个链接解决方案的方式来使其特定于postgres .text和原始代码无需额外工作.| 归档时间: |
|
| 查看次数: |
14693 次 |
| 最近记录: |