Varför det händer
Problemet är att PostgreSQL är alltför strikt när det gäller casts mellan text- och icke-textdatatyper. Den tillåter inte en implicit cast (en utan en CAST
). eller ::
i SQL) från en texttyp som text
eller varchar
(character varying
) till en textliknande icke-texttyp som json
, xml
, etc.
PgJDBC-drivrutinen anger datatypen för varchar
när du anropar setString
för att tilldela en parameter. Om databastypen för kolumnen, funktionsargument, etc, faktiskt inte är varchar
eller text
, men istället en annan typ får du ett typfel. Detta gäller även för en hel del andra förare och ORM.
PgJDBC:stringtype=unspecified
Det bästa alternativet när du använder PgJDBC är i allmänhet att skicka parametern stringtype=unspecified
. Detta åsidosätter standardbeteendet för att skicka setString
värden som varchar
och istället överlåter det till databasen att "gissa" deras datatyp. I nästan alla fall gör detta precis vad du vill, och skickar strängen till indatavalidatorn för den typ du vill lagra.
Alla:CREATE CAST ... WITH FUNCTION ...
Du kan istället CREATE CAST
att definiera en datatypspecifik cast för att tillåta detta på typ-för-typ-basis, men detta kan ha biverkningar på andra ställen. Om du gör detta, gör inte använd WITHOUT FUNCTION
casts kommer de att kringgå typvalidering och resultera i fel. Du måste använda inmatnings-/valideringsfunktionen för datatypen. Använder CREATE CAST
är lämplig för användare av andra databasdrivrutiner som inte har något sätt att stoppa drivrutinen som anger typen för sträng-/textparametrar.
t.ex.
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;
Alla:Anpassad typhanterare
Om din ORM tillåter kan du implementera en anpassad typhanterare för datatypen och den specifika ORM. Detta är mest användbart när du använder inbyggd Java-typ som mappar väl till PostgreSQL-typen, snarare än att använda String
, men det kan också fungera om din ORM låter dig specificera typhanterare med anteckningar etc.
Metoder för att implementera anpassade typhanterare är drivrutins-, språk- och ORM-specifika. Här är ett exempel för Java och Hibernate för json
.
PgJDBC:skriv hanterare med PGObject
Om du använder en inbyggd Java-typ i Java kan du utöka PGObject
för att tillhandahålla en PgJDBC-typmappning för din typ. Du kommer förmodligen också att behöva implementera en ORM-specifik typhanterare för att använda ditt PGObject
, eftersom de flesta ORM:er bara anropar toString
på typer som de inte känner igen. Detta är det föredragna sättet att mappa komplexa typer mellan Java och PostgreSQL, men också det mest komplexa.
PgJDBC:Typhanterare med setObject(int, Object)
Om du använder String
för att hålla värdet i Java, snarare än en mer specifik typ, kan du anropa JDBC-metoden setObject(integer, Object)
för att lagra strängen utan någon speciell datatyp specificerad. JDBC-drivrutinen skickar strängrepresentationen, och databasen kommer att sluta sig till typen från destinationskolumntypen eller funktionsargumenttypen.
Se även
Frågor:
- Mappa postgreSQL JSON-kolumn till Hibernate-värdetyp
- Är JPA (EclipseLink) anpassade typer möjliga?
Externt:
- 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