我正在尝试将Postgres自定义类型(名为transmission_result)映射到Hibernate / JPA POJO。postgres自定义类型或多或少是字符串值的枚举类型。
我创建了一个名为PGEnumUserType的自定义EnumUserType以及一个表示postgres枚举值的枚举类。当我对一个真实的数据库运行它时,我收到以下错误:’ERROR:列“状态”的类型为transmission_result,但表达式的类型字符不同提示:您将需要重写或强制转换表达式。位置:135’
看到此消息后,我发现需要将SqlTypes更改为Types.OTHER。但这会破坏我的集成测试(在内存DB中使用HyperSQL),并显示以下消息:’引起原因:java.sql.SQLException:在语句[select enrollment0 。“ id”作为id1_47_0,enrollment0 。“ tpa_approval_id”作为tpa2_47_0_中找不到表,将注册0 。“ tpa_status_code”设置为tpa3_47_0_,将注册0 。“ status_message”作为状态4_47_0,将注册0 。“ approval_id”作为批准5_47_0,将注册0_。“发送日期”作为transmis6_47_0_作为状态4“将发送,将注册0_从” 0“发送给注册4_。传输” enrollment0_,其中enrollment0 _。“ id” =?]’
我不确定为什么更改sqlType会导致此错误。任何帮助表示赞赏。
JPA /hibernate实体:
@Entity @Access(javax.persistence.AccessType.PROPERTY) @Table(name="transmissions") public class EnrollmentCycleTransmission { // elements of enum status column private static final String ACCEPTED_TRANSMISSION = "accepted"; private static final String REJECTED_TRANSMISSION = "rejected"; private static final String DUPLICATE_TRANSMISSION = "duplicate"; private static final String EXCEPTION_TRANSMISSION = "exception"; private static final String RETRY_TRANSMISSION = "retry"; private Long transmissionID; private Long approvalID; private Long transmitterID; private TransmissionStatusType transmissionStatus; private Date transmissionDate; private String TPAApprovalID; private String TPAStatusCode; private String TPAStatusMessage; @Column(name = "id") @Id @GeneratedValue(strategy=GenerationType.AUTO) public Long getTransmissionID() { return transmissionID; } public void setTransmissionID(Long transmissionID) { this.transmissionID = transmissionID; } @Column(name = "approval_id") public Long getApprovalID() { return approvalID; } public void setApprovalID(Long approvalID) { this.approvalID = approvalID; } @Column(name = "transmitter") public Long getTransmitterID() { return transmitterID; } public void setTransmitterID(Long transmitterID) { this.transmitterID = transmitterID; } @Column(name = "status") @Type(type = "org.fuwt.model.PGEnumUserType" , parameters ={@org.hibernate.annotations.Parameter(name = "enumClassName",value = "org.fuwt.model.enrollment.TransmissionStatusType")} ) public TransmissionStatusType getTransmissionStatus() { return this.transmissionStatus ; } public void setTransmissionStatus(TransmissionStatusType transmissionStatus) { this.transmissionStatus = transmissionStatus; } @Column(name = "transmission_date") public Date getTransmissionDate() { return transmissionDate; } public void setTransmissionDate(Date transmissionDate) { this.transmissionDate = transmissionDate; } @Column(name = "tpa_approval_id") public String getTPAApprovalID() { return TPAApprovalID; } public void setTPAApprovalID(String TPAApprovalID) { this.TPAApprovalID = TPAApprovalID; } @Column(name = "tpa_status_code") public String getTPAStatusCode() { return TPAStatusCode; } public void setTPAStatusCode(String TPAStatusCode) { this.TPAStatusCode = TPAStatusCode; } @Column(name = "status_message") public String getTPAStatusMessage() { return TPAStatusMessage; } public void setTPAStatusMessage(String TPAStatusMessage) { this.TPAStatusMessage = TPAStatusMessage; } }
自定义EnumUserType:
public class PGEnumUserType implements UserType, ParameterizedType { private Class<Enum> enumClass; public PGEnumUserType(){ super(); } public void setParameterValues(Properties parameters) { String enumClassName = parameters.getProperty("enumClassName"); try { enumClass = (Class<Enum>) Class.forName(enumClassName); } catch (ClassNotFoundException e) { throw new HibernateException("Enum class not found ", e); } } public int[] sqlTypes() { return new int[] {Types.VARCHAR}; } public Class returnedClass() { return enumClass; } public boolean equals(Object x, Object y) throws HibernateException { return x==y; } public int hashCode(Object x) throws HibernateException { return x.hashCode(); } public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException { String name = rs.getString(names[0]); return rs.wasNull() ? null: Enum.valueOf(enumClass,name); } public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException { if (value == null) { st.setNull(index, Types.VARCHAR); } else { st.setString(index,((Enum) value).name()); } } public Object deepCopy(Object value) throws HibernateException { return value; } public boolean isMutable() { return false; //To change body of implemented methods use File | Settings | File Templates. } public Serializable disassemble(Object value) throws HibernateException { return (Enum) value; } public Object assemble(Serializable cached, Object owner) throws HibernateException { return cached; } public Object replace(Object original, Object target, Object owner) throws HibernateException { return original; } public Object fromXMLString(String xmlValue) { return Enum.valueOf(enumClass, xmlValue); } public String objectToSQLString(Object value) { return '\'' + ( (Enum) value ).name() + '\''; } public String toXMLString(Object value) { return ( (Enum) value ).name(); } }
枚举类:
public enum TransmissionStatusType { accepted, rejected, duplicate, exception, retry}
我想到了。我需要在nullSafeSet函数中使用setObject而不是setString,并将Types.OTHER作为java.sql.type传入,以使jdbc知道它是postgres类型。
public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException { if (value == null) { st.setNull(index, Types.VARCHAR); } else { // previously used setString, but this causes postgresql to bark about incompatible types. // now using setObject passing in the java type for the postgres enum object // st.setString(index,((Enum) value).name()); st.setObject(index,((Enum) value), Types.OTHER); } }