2011-09-29 10 views
6

Próbuję odwzorować niestandardowy typ postgre, o nazwie transmission_result, na POJO Hibernacji/JPA. Typ niestandardowy Postgres to mniej więcej typ wartości ciągowych enum.Próba mapowania wyrażeń postgresowych na Hibernate/JPA pojo

Utworzono niestandardowy typ EnumUserType o nazwie PGEnumUserType, a także klasę wyliczającą reprezentującą wyliczone wartości postgresu. Po uruchomieniu tego w stosunku do rzeczywistej bazy danych, pojawia się następujący błąd: "BŁĄD: kolumna" status "jest typu transmission_result, ale wyrażenie ma charakter zmienny. Wskazówka: Konieczne będzie przepisanie lub rzutowanie wyrażenia. Pozycja: 135 '

Po zobaczeniu tego, doszedłem do wniosku, że muszę zmienić SqlTypes na Types.OTHER. Ale w ten sposób łamie moje testy integracyjne (przy użyciu HyperSQL w DB pamięci) z komunikatem: "Powodowane przez: java.sql.SQLException: Tabela nie znaleziono w oświadczeniu [wybierz zapisanie0 _." Id "jako id1_47_0_, rejestracja0 _." Tpa_approval_id "jako tpa2_47_0_, rejestracja0 _. "tpa_status_code" jako tpa3_47_0_, rejestracja0 _. "status_message" jako status4_47_0_, rejestracja0 _. "identyfikator_agacji" jako zatwierdzenie5_47_0_, rejestracja0 _. "transmisja_data" jako transmis6_47_0_, rejestracja0 _. "status" jako status7_47_0_, rejestracja0 _. "nadajnik" jako nadawca8_47_0_ z "transmisje" rejestracja0_ gdzie rejestracja0 _. "id" =?] "

Nie jestem pewien, dlaczego zmiana sqlType powoduje ten błąd. Każda pomoc jest doceniana.

JPA/Hibernate Podmiot:

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

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

klasa ENUM:

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

Odpowiedz

9

I zdobione. Potrzebowałem użyć setObject zamiast setString w funkcji nullSafeSet i przekazać Types.OTHER jako java.sql.type, aby jdbc wiedział, że jest to typ 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

Jak explained in this article, zakładając, że masz następujące post_status_info typu enum w PostgreSQL:

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

można łatwo mapować Java Enum z typem kolumny PostgreSQL Enum stosując następujący zwyczaj hibernacji Typ:

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

Aby z niego skorzystać, należy dodać adnotację do tego pola z adnotacją Hibernate @Type, jak pokazano na poniższym przykładzie:

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

To wszystko, działa jak urok. Oto test on GitHub that proves it.

Powiązane problemy