2011-09-29 11 views
6

Estoy tratando de asignar un tipo personalizado de postgres, llamado transmission_result, a un POJO de Hibernate/JPA. El tipo personalizado postgres es más o menos un tipo enum de valores de cadena.Intentando asignar postgres enum a Hibernate/JPA pojo

He creado un EnumUserType personalizado llamado PGEnumUserType, así como una clase enum que representa los valores enumerados de postgres. Cuando ejecuto esto en una base de datos real, recibo el siguiente error: 'ERROR: columna' 'estado' 'es de tipo transmission_result pero la expresión es de tipo carácter variable Sugerencia: Deberá reescribir o convertir la expresión. Posición: 135 '

Al ver esto, pensé que necesitaba cambiar mis tipos de Sql a Types.OTHER. Pero al hacerlo, rompe mis pruebas de integración (usando HyperSQL en la base de datos de memoria) con el mensaje: 'Causado por: java.sql.SQLException: Tabla no encontrada en la declaración [select enrollment0 _. "Id" como id1_47_0_, enrollment0 _. "Tpa_approval_id" as tpa2_47_0_, registration0 _. "tpa_status_code" como tpa3_47_0_, enrollment0 _. "status_message" como status4_47_0_, inscripción0 _. "approval_id" como approval5_47_0_, inscripción0 _. "transmission_date" como transmis6_47_0_, inscripción0 _. "estado" como status7_47_0_, inscripción0 _. "transmisor" como transmit8_47_0_ de "transmisiones" inscripción0_ donde inscripción0 _. "id" =?] '

No estoy seguro de por qué cambiar los resultados de sqlType en este error. Cualquier ayuda es apreciada.

JPA/Hibernate Entidad:

@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; 
} 
} 

personalizada 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(); 
} 
} 

clase Enum:

public enum TransmissionStatusType { 
accepted, 
rejected, 
duplicate, 
exception, 
retry} 

Respuesta

9

lo he descubierto. Necesitaba usar setObject en lugar de setString en la función nullSafeSet y pasar los Types.OTHER como java.sql.type para que jdbc supiera que era un tipo de 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); 
    } 
} 
0

Mientras explained in this article, suponiendo que se dispone de los siguientes post_status_info tipo de enumeración en PostgreSQL:

CREATE TYPE post_status_info AS ENUM (
    'PENDING', 
    'APPROVED', 
    'SPAM' 
) 

Puede asignar fácilmente Java Enum a un tipo de columna PostgreSQL Enum utilizando el siguiente encargo Hibernate Tipo:

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 
      ); 
     } 
    } 
} 

Para utilizarlo, debe anotar el campo con la anotación Hibernate @Type como se ilustra en el siguiente ejemplo:

@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 
} 

Eso es todo, funciona como un amuleto. Aquí hay un test on GitHub that proves it.

Cuestiones relacionadas