sql >> Base de Datos >  >> RDS >> PostgreSQL

El almacenamiento de json, jsonb, hstore, xml, enum, ipaddr, etc. falla con la columna x es de tipo json pero la expresión es de tipo carácter variable

Por qué sucede

El problema es que PostgreSQL es demasiado estricto con respecto a las conversiones entre tipos de datos de texto y no texto. No permitirá un lanzamiento implícito (uno sin un CAST o :: en el SQL) de un tipo de texto como text o varchar (character varying ) a un tipo de texto sin texto como json , xml , etc.

El controlador PgJDBC especifica el tipo de datos de varchar cuando llamas a setString para asignar un parámetro. Si el tipo de base de datos de la columna, el argumento de la función, etc., no es realmente varchar o text , pero en lugar de otro tipo, obtienes un error de tipo. Esto también se aplica a muchos otros controladores y ORM.

PgJDBC:stringtype=unspecified

La mejor opción cuando se usa PgJDBC generalmente es pasar el parámetro stringtype=unspecified . Esto anula el comportamiento predeterminado de pasar setString valores como varchar y en su lugar deja que la base de datos "adivine" su tipo de datos. En casi todos los casos, esto hace exactamente lo que desea, pasando la cadena al validador de entrada para el tipo que desea almacenar.

Todos:CREATE CAST ... WITH FUNCTION ...

En su lugar, puedes CREATE CAST para definir una conversión específica de tipo de datos para permitir esto tipo por tipo, pero esto puede tener efectos secundarios en otros lugares. Si haces esto, no usar WITHOUT FUNCTION conversiones, omitirán la validación de tipos y generarán errores. Debe utilizar la función de entrada/validación para el tipo de datos. Usando CREATE CAST es adecuado para usuarios de otros controladores de base de datos que no tienen forma de detener el controlador que especifica el tipo de parámetros de cadena/texto.

por ejemplo

CREATE OR REPLACE FUNCTION json_intext(text) RETURNS json AS $$
SELECT json_in($1::cstring); 
$$ LANGUAGE SQL IMMUTABLE;

CREATE CAST (text AS json) 
WITH FUNCTION json_intext(text) AS IMPLICIT;

Todos:controlador de tipo personalizado

Si su ORM lo permite, puede implementar un controlador de tipo personalizado para el tipo de datos y ese ORM específico. Esto es especialmente útil cuando usa un tipo de Java nativo que se asigna bien al tipo de PostgreSQL, en lugar de usar String , aunque también puede funcionar si su ORM le permite especificar controladores de tipos mediante anotaciones, etc.

Los métodos para implementar controladores de tipos personalizados son específicos del controlador, el idioma y el ORM. Aquí hay un ejemplo para Java e Hibernate para json .

PgJDBC:manejador de tipo usando PGObject

Si está utilizando un tipo de Java nativo en Java, puede extender PGObject para proporcionar una asignación de tipo PgJDBC para su tipo. Probablemente también necesitará implementar un controlador de tipo específico de ORM para usar su PGObject , ya que la mayoría de los ORM solo llamarán a toString en tipos que no reconocen. Esta es la forma preferida de mapear tipos complejos entre Java y PostgreSQL, pero también la más compleja.

PgJDBC:manejador de tipo usando setObject(int, Object)

Si está utilizando String para mantener el valor en Java, en lugar de un tipo más específico, puede invocar el método JDBC setObject(integer, Object) para almacenar la cadena sin especificar ningún tipo de datos en particular. El controlador JDBC enviará la representación de cadena y la base de datos deducirá el tipo del tipo de columna de destino o del tipo de argumento de función.

Véase también

Preguntas:

  • Asignación de la columna JSON de postgreSQL al tipo de valor de Hibernate
  • ¿Son posibles los tipos personalizados JPA (EclipseLink)?

Externo:

  • http://www.postgresql.org/message-id/[email protected]
  • https://github.com/pgjdbc/pgjdbc/issues/265
  • http://www.pateldenish.com/2013/05/inserting-json-data-into-postgres-using-jdbc-driver.html