PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

La memorizzazione di json, jsonb, hstore, xml, enum, ipaddr, ecc. non riesce con la colonna x di tipo json ma l'espressione è di tipo carattere variabile

Perché succede

Il problema è che PostgreSQL è eccessivamente severo riguardo ai cast tra tipi di dati testuali e non testuali. Non consentirà un cast implicito (uno senza un CAST o :: nell'SQL) da un tipo di testo come text o varchar (character varying ) a un tipo non testuale simile a un testo come json , xml , ecc.

Il driver PgJDBC specifica il tipo di dati di varchar quando chiami setString per assegnare un parametro. Se il tipo di database della colonna, l'argomento della funzione, ecc. non è effettivamente varchar o text , ma invece di un altro tipo, viene visualizzato un errore di tipo. Questo vale anche per molti altri driver e ORM.

PgJDBC:stringtype=unspecified

L'opzione migliore quando si utilizza PgJDBC è generalmente passare il parametro stringtype=unspecified . Questo sovrascrive il comportamento predefinito di passaggio di setString valori come varchar e invece lascia al database di "indovinare" il loro tipo di dati. In quasi tutti i casi questo fa esattamente quello che vuoi, passando la stringa al validatore di input per il tipo che vuoi memorizzare.

Tutti:CREATE CAST ... WITH FUNCTION ...

Puoi invece CREATE CAST per definire un cast specifico del tipo di dati per consentire ciò tipo per tipo, ma ciò può avere effetti collaterali altrove. Se lo fai, non usa WITHOUT FUNCTION cast, ignoreranno la convalida del tipo e genereranno errori. È necessario utilizzare la funzione di input/convalida per il tipo di dati. Usando CREATE CAST è adatto per utenti di altri driver di database che non hanno alcun modo per fermare il driver specificando il tipo per i parametri stringa/testo.

es.

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;

Tutti:gestore di tipi personalizzato

Se il tuo ORM lo consente, puoi implementare un gestore di tipi personalizzato per il tipo di dati e quello specifico ORM. Questo è utile soprattutto quando stai usando un tipo Java nativo che si associa bene al tipo PostgreSQL, piuttosto che usare String , sebbene possa funzionare anche se il tuo ORM ti consente di specificare gestori di tipi utilizzando annotazioni ecc.

I metodi per l'implementazione di gestori di tipi personalizzati sono specifici del driver, della lingua e dell'ORM. Ecco un esempio per Java e Hibernate per json .

PgJDBC:tipo handler usando PGObject

Se stai usando un tipo Java nativo in Java, puoi estendere PGObject per fornire una mappatura del tipo PgJDBC per il tuo tipo. Probabilmente dovrai anche implementare un gestore di tipi specifico per ORM per usare il tuo PGObject , poiché la maggior parte degli ORM chiamerà semplicemente toString sui tipi che non riconoscono. Questo è il modo preferito per mappare tipi complessi tra Java e PostgreSQL, ma anche il più complesso.

PgJDBC:tipo handler usando setObject(int, Object)

Se stai usando String per mantenere il valore in Java, piuttosto che un tipo più specifico, puoi invocare il metodo JDBC setObject(integer, Object) per memorizzare la stringa senza un particolare tipo di dati specificato. Il driver JDBC invierà la rappresentazione della stringa e il database dedurrà il tipo dal tipo di colonna di destinazione o dal tipo di argomento della funzione.

Vedi anche

Domande:

  • Mappatura della colonna JSON postgreSQL al tipo di valore Ibernazione
  • Sono possibili tipi personalizzati JPA (EclipseLink)?

Esterno:

  • 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