PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Das Speichern von json, jsonb, hstore, xml, enum, ipaddr usw. schlägt fehl, wenn die Spalte x vom Typ json ist, aber der Ausdruck vom Typ Zeichen variiert

Warum es passiert

Das Problem ist, dass PostgreSQL bei Umwandlungen zwischen Text- und Nicht-Text-Datentypen zu streng ist. Es erlaubt keine implizite Umwandlung (eine ohne CAST oder :: im SQL) von einem Texttyp wie text oder varchar (character varying ) in einen textähnlichen Nicht-Texttyp wie json , xml usw.

Der PgJDBC-Treiber gibt den Datentyp von varchar an wenn Sie setString aufrufen einen Parameter zuweisen. Wenn der Datenbanktyp der Spalte, des Funktionsarguments usw. nicht wirklich varchar ist oder text , aber statt eines anderen Typs erhalten Sie einen Typfehler. Dies gilt auch für viele andere Treiber und ORMs.

PgJDBC:stringtype=unspecified

Die beste Option bei der Verwendung von PgJDBC ist im Allgemeinen die Übergabe des Parameters stringtype=unspecified . Dies überschreibt das Standardverhalten der Übergabe von setString Werte als varchar und überlässt es stattdessen der Datenbank, ihren Datentyp zu "erraten". In fast allen Fällen macht dies genau das, was Sie wollen, und übergibt den String an den Eingabe-Validierer für den Typ, den Sie speichern möchten.

Alle:CREATE CAST ... WITH FUNCTION ...

Sie können stattdessen CREATE CAST eine datentypspezifische Umwandlung zu definieren, um dies Typ für Typ zu ermöglichen, aber dies kann an anderer Stelle Nebenwirkungen haben. Wenn Sie dies tun, tun Sie es nicht Verwenden Sie WITHOUT FUNCTION Umwandlungen umgehen, umgehen sie die Typvalidierung und führen zu Fehlern. Sie müssen die Eingabe-/Validierungsfunktion für den Datentyp verwenden. Mit CREATE CAST eignet sich für Benutzer anderer Datenbanktreiber, die keine Möglichkeit haben, den Treiber anzuhalten, der den Typ für Zeichenfolgen-/Textparameter angibt.

z. B.

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;

Alle:Handler für benutzerdefinierte Typen

Wenn Ihr ORM dies zulässt, können Sie einen benutzerdefinierten Typhandler für den Datentyp und dieses spezifische ORM implementieren. Dies ist vor allem dann nützlich, wenn Sie einen nativen Java-Typ verwenden, der gut auf den PostgreSQL-Typ abgebildet wird, anstatt String zu verwenden , obwohl es auch funktionieren kann, wenn Ihr ORM die Angabe von Typhandlern mithilfe von Anmerkungen usw. zulässt.

Methoden zum Implementieren benutzerdefinierter Typhandler sind treiber-, sprach- und ORM-spezifisch. Hier ist ein Beispiel für Java und Hibernate für json .

PgJDBC:Typ-Handler mit PGObject

Wenn Sie einen nativen Java-Typ in Java verwenden, können Sie PGObject erweitern um eine PgJDBC-Typzuordnung für Ihren Typ bereitzustellen. Sie müssen wahrscheinlich auch einen ORM-spezifischen Typ-Handler implementieren, um Ihr PGObject zu verwenden , da die meisten ORMs einfach toString aufrufen auf Typen, die sie nicht erkennen. Dies ist der bevorzugte Weg, um komplexe Typen zwischen Java und PostgreSQL abzubilden, aber auch der komplexeste.

PgJDBC:Typ-Handler mit setObject(int, Object)

Wenn Sie String verwenden Um den Wert in Java anstelle eines spezifischeren Typs zu speichern, können Sie die JDBC-Methode setObject(integer, Object) aufrufen zum Speichern der Zeichenfolge ohne Angabe eines bestimmten Datentyps. Der JDBC-Treiber sendet die Zeichenfolgendarstellung, und die Datenbank leitet den Typ vom Zielspaltentyp oder Funktionsargumenttyp ab.

Siehe auch

Fragen:

  • PostgreSQL-JSON-Spalte dem Hibernate-Werttyp zuordnen
  • Sind JPA (EclipseLink) benutzerdefinierte Typen möglich?

Extern:

  • 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