PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Armazenar json, jsonb, hstore, xml, enum, ipaddr, etc falha com a coluna x é do tipo json, mas a expressão é do tipo caractere variando

Por que isso acontece


O problema é que o PostgreSQL é muito rígido com relação a conversões entre tipos de dados de texto e não-texto. Não permitirá uma conversão implícita (uma sem um CAST ou :: no SQL) de um tipo de texto como text ou varchar (character varying ) para um tipo não-texto semelhante a texto como json , xml , etc

O driver PgJDBC especifica o tipo de dados de varchar quando você chama setString para atribuir um parâmetro. Se o tipo de banco de dados da coluna, argumento da função, etc, não for realmente varchar ou text , mas em vez de outro tipo, você obtém um erro de tipo. Isso também é verdade para muitos outros drivers e ORMs.

PgJDBC:stringtype=unspecified


A melhor opção ao usar o PgJDBC é geralmente passar o parâmetro stringtype=unspecified . Isso substitui o comportamento padrão de passar setString valores como varchar e, em vez disso, deixa para o banco de dados "adivinhar" seu tipo de dados. Em quase todos os casos, isso faz exatamente o que você deseja, passando a string para o validador de entrada do tipo que deseja armazenar.

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


Em vez disso, você pode CREATE CAST para definir uma conversão específica de tipo de dados para permitir isso tipo por tipo, mas isso pode ter efeitos colaterais em outros lugares. Se você fizer isso, não use WITHOUT FUNCTION casts, eles ignorarão a validação de tipo e resultarão em erros. Você deve usar a função de entrada/validação para o tipo de dados. Usando CREATE CAST é adequado para usuários de outros drivers de banco de dados que não têm como parar o driver especificando o tipo de parâmetros de string/texto.

por exemplo.
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:manipulador de tipo personalizado


Se o seu ORM permitir, você poderá implementar um manipulador de tipo personalizado para o tipo de dados e esse ORM específico. Isso é útil principalmente quando você está usando o tipo Java nativo que mapeia bem para o tipo PostgreSQL, em vez de usar String , embora também possa funcionar se seu ORM permitir que você especifique manipuladores de tipo usando anotações etc.

Os métodos para implementar manipuladores de tipo personalizados são específicos de driver, idioma e ORM. Aqui está um exemplo para Java e Hibernate para json .

PgJDBC:manipulador de tipos usando PGObject


Se você estiver usando um tipo de Java nativo em Java, poderá estender PGObject para fornecer um mapeamento de tipo PgJDBC para seu tipo. Você provavelmente também precisará implementar um manipulador de tipo específico de ORM para usar seu PGObject , já que a maioria dos ORMs apenas chamará toString em tipos que eles não reconhecem. Essa é a maneira preferida de mapear tipos complexos entre Java e PostgreSQL, mas também a mais complexa.

PgJDBC:manipulador de tipos usando setObject(int, Object)


Se você estiver usando String para manter o valor em Java, em vez de um tipo mais específico, você pode invocar o método JDBC setObject(integer, Object) para armazenar a string sem nenhum tipo de dados específico especificado. O driver JDBC enviará a representação de string e o banco de dados inferirá o tipo do tipo de coluna de destino ou do tipo de argumento da função.

Veja também


Questões:
  • Mapeando a coluna JSON do postgreSQL para o tipo de valor do Hibernate
  • Os tipos personalizados JPA (EclipseLink) são possíveis?

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