Grails, PostgreSQL und Enums

Momentan bin ich dabei eine Webanwendung mit Grails zu bauen. In der dieser Webanwendung zu grunde liegenden Datenbank (PostgreSQL), habe ich eigene Datentypen in Form von Enums erstellt. Zum Beispiel den folgenden:

  1. CREATE TYPE public.payment_method AS
  2. ENUM ('CASH','CASH_CARD');

Nachdem der Enum auch in der Webanwendung erstellt wurde,

  1. public enum PaymentMethods {
  2.    cash, cash_card
  3. }

wollte ich diesen dann in Grails wie folgt einbinden.

  1. class Invoice {
  2.    static mapping = {
  3.    ..
  4.    paymentMethod column: 'payment_method'
  5.    ..
  6.    }
  7.    PaymentMethods paymentMethod
  8. }

Doch ich bekam folgende Fehlermeldung:

FEHLER: Spalte »payment_method« hat Typ payment_method, aber der Ausdruck hat Typ character varying Hinweis: Sie müssen den Ausdruck umschreiben oder eine Typumwandlung vornehmen.

Mit den standard Typen wie String, Integer oder Date kann Grails umgehen, mit einem Enum anscheinend jedoch nicht. Ein Blick in die Grails-Dokumentation offenbart folgendes:

GORM supports configuration of Hibernate types with the DSL using the type attribute. This includes specifing user types that implement the Hibernate org.hibernate.usertype.UserType interface, which allows complete customization of how a type is persisted.

Nach kurzer Zeit stieß ich auf ein Beispiel für die Implementierung eines eigenen UserTypes. Doch da ich mehrere Enums benutze und nicht für jeden Enum eine extra UserType-Klasse definieren wollte, suchte ich weiter. Die Antwort fand ich dann auf diesem Blog. Dort wird erklärt wie ein parametrisierten UserType erstellt wird. Durch die Mischung beider Beispiele entstand die folgende Klasse, die es ermöglicht in Grails mit verschiedenen Enums zu arbeiten.

  1. public class PGEnumUserType implements UserType, ParameterizedType {
  2.    private static final SQL_TYPES = [Types.VARCHAR] as int[]	
  3.    private Class enumClass;	
  4.    @Override
  5.    public void setParameterValues(Properties parameters) {
  6.       String enumClassName = parameters.getProperty("enumClassName")
  7.       try { enumClass = (Class) Class.forName(enumClassName) }
  8.       catch (ClassNotFoundException cnfe) { throw new HibernateException("Enum class not found", cnfe) }
  9.    }
  10.    @Override
  11.    public Object assemble(Serializable cached, Object owner) throws HibernateException { return cached }
  12.    @Override
  13.    public Object deepCopy(Object value) throws HibernateException { return value }
  14.    @Override
  15.    public Serializable disassemble(Object value) throws HibernateException { return value }
  16.    @Override
  17.    public boolean equals(Object x, Object y) throws HibernateException { return x.equals(y) }
  18.    @Override
  19.    public int hashCode(Object x) throws HibernateException { return x.hashCode() }
  20.    @Override
  21.    public boolean isMutable() { return false }
  22.    @Override
  23.    public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException {
  24.       def result = rs.getObject(names[0]);
  25.       if (result) { return Enum.valueOf(enumClass, (String) result) }
  26.       else { return null }
  27.    }
  28.    @Override
  29.    public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException {
  30.       if (value) { st.setObject(index, ((Enum)value), 1111); }
  31.       else { st.setNull(index, Types.VARCHAR) }
  32.    }
  33.    @Override
  34.    public Object replace(Object original, Object target, Object owner) throws HibernateException { return original }
  35.    @Override
  36.    public Class returnedClass() { return enumClass }
  37.    @Override
  38.    public int[] sqlTypes() { return SQL_TYPES }
  39. }

Jetzt muss diese Klasse nur noch in Grails eingebunden und das zu verwendende Enum übergeben werden:

  1. class Invoice {
  2.    static mapping = {
  3.    ..
  4.    paymentMethod column: 'payment_method', type: PGEnumUserType, params : [ enumClassName: "package.PaymentMethods"]
  5.    ..
  6.    }
  7.    PaymentMethods paymentMethod
  8. }

Jetzt kann Grails mit Enums arbeiten.

Dieser Beitrag wurde unter Grails, Hibernate, PostgreSQL abgelegt und mit , verschlagwortet. Setze ein Lesezeichen auf den Permalink.

Hinterlasse eine Antwort

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert *

Du kannst folgende HTML-Tags benutzen: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre lang="" line="" escaped="" cssfile="">