persistir mapear enumerated enum annotation java postgresql jpa

java - mapear - persistir enum jpa



Enumeraciones de Java Enums, JPA y Postgres: ¿cómo puedo hacer que funcionen juntas? (3)

Tenemos una base de datos de Postgres con enums de postgres. Estamos empezando a construir JPA en nuestra aplicación. También tenemos enums de Java que reflejan las enums de postgres. Ahora la gran pregunta es cómo lograr que JPA comprenda las enums de Java en un lado y las enums de postgres en el otro. El lado de Java debería ser bastante fácil, pero no estoy seguro de cómo hacer el lado del postgres.


Archivé un informe de error con un parche incluido para Hibernate: HHH-5188

El parche funciona para que lea una enumeración PostgreSQL en una enumeración Java usando JPA.


De hecho, he estado usando una forma más simple que la que tiene PGObject and Converters. Dado que en las enums de Postgres se convierten de forma natural en texto de entrada, solo tienes que dejar que haga lo que mejor hace. Tomaré el ejemplo de humor de Arjan, si no le importa:

El tipo enum en Postgres:

CREATE TYPE mood AS ENUM (''sad'', ''ok'', ''happy'');

La clase y la enumeración en Java:

public @Entity class Person { public static enum Mood {sad, ok, happy}; @Enumerated(EnumType.STRING) Mood mood;

}

Esa etiqueta @Enumerated dice que la serialización / deserialización de la enumeración debe hacerse en texto. Sin él, usa int, que es más problemático que cualquier otra cosa.

En este punto tienes dos opciones. Usted:

  1. Agregue stringtype = unspecified a la cadena de conexión, como se explica en los parámetros de conexión JDBC . Esto permite a Postgres adivinar el tipo del lado derecho y convertir todo adecuadamente, ya que recibe algo así como ''enum = unknown'', que es una expresión que ya sabe qué hacer (introduce el valor? En el deserializador del tipo izquierdo). Esta es la opción preferida, ya que debería funcionar para todos los UDT simples como enums de una vez.

O:

  1. Cree una conversión implícita de varchar a la enumeración en la base de datos. Entonces en este segundo caso la base de datos recibe alguna asignación o comparación como ''enum = varchar'' y encuentra una regla en su catálogo interno que dice que puede pasar el valor de la derecha a través de la función de serialización de varchar seguido de la función de deserialización del enum. Eso es más pasos de los que deberían ser necesarios; y tener demasiados moldes implícitos en el catálogo puede hacer que las consultas arbitrarias tengan interpretaciones ambiguas, así que úselo con moderación. La creación del elenco es:

    CREATE CAST (CARACTER VARYING como estado de ánimo) WITH INOUT AS IMPLICIT;

Debería funcionar solo con eso.


Esto implica hacer múltiples asignaciones.

Primero, el controlador JDBC devuelve una enumeración de Postgres como una instancia de tipo PGObject. La propiedad type de este tiene el nombre de su enum postgres, y la propiedad del valor es su valor. (Sin embargo, el ordinal no se almacena, por lo que técnicamente ya no es una enumeración y posiblemente completamente inútil debido a esto)

De todos modos, si tienes una definición como esta en Postgres:

CREATE TYPE mood AS ENUM (''sad'', ''ok'', ''happy'');

Entonces el conjunto de resultados contendrá un PGObject con el tipo "estado de ánimo" y el valor "feliz" para una columna que tenga este tipo de enumeración y una fila con el valor "feliz".

Lo siguiente que hay que hacer es escribir un código de interceptor que se encuentre entre el punto donde JPA lee del conjunto de resultados sin procesar y establece el valor en su entidad. Por ejemplo, supongamos que tiene la siguiente entidad en Java:

public @Entity class Person { public static enum Mood {sad, ok, happy} @Id Long ID; Mood mood; }

Desafortunadamente, JPA no ofrece un punto de interceptación fácil donde se puede hacer la conversión de PGObject a Java enum Mood. Sin embargo, la mayoría de los vendedores de JPA tienen algún soporte propietario para esto. Hibernate, por ejemplo, tiene las anotaciones TypeDef y Type para esto (de Hibernate-annotations.jar).

@TypeDef(name="myEnumConverter", typeClass=MyEnumConverter.class) public @Entity class Person { public static enum Mood {sad, ok, happy} @Id Long ID; @Type(type="myEnumConverter") Mood mood;

Estos le permiten suministrar una instancia de UserType (desde Hibernate-core.jar) que hace la conversión real:

public class MyEnumConverter implements UserType { private static final int[] SQL_TYPES = new int[]{Types.OTHER}; public Object nullSafeGet(ResultSet arg0, String[] arg1, Object arg2) throws HibernateException, SQLException { Object pgObject = arg0.getObject(X); // X is the column containing the enum try { Method valueMethod = pgObject.getClass().getMethod("getValue"); String value = (String)valueMethod.invoke(pgObject); return Mood.valueOf(value); } catch (Exception e) { e.printStackTrace(); } return null; } public int[] sqlTypes() { return SQL_TYPES; } // Rest of methods omitted }

Esta no es una solución de trabajo completa, sino solo un indicador rápido con la esperanza de que sea la dirección correcta.