Cra*_*ger 20 postgresql json casting jpa jdbc
当使用PostgreSQL将数据存储在一个绳状验证类型的字段,如xml,json,jsonb,xml,ltree,等等,所述INSERT或UPDATE失败等错误:
column "the_col" is of type json but expression is of type character varying
Run Code Online (Sandbox Code Playgroud)
... 要么
column "the_col" is of type json but expression is of type text
Run Code Online (Sandbox Code Playgroud)
为什么?我能做些什么呢?
我正在使用JDBC(PgJDBC).
这通过Hibernate,JPA和各种其他抽象层发生.
PostgreSQL团队的"标准"建议是CAST在SQL中使用a .这对于使用查询生成器或ORM的人来说没有用,特别是如果这些系统没有对数据库类型的明确支持json,因此它们通过String应用程序进行映射.
一些ORM允许实现自定义类型处理程序,但我真的不想为每个ORM编写每个数据类型的自定义处理程序,例如Hibernate上的json,EclipseLink上的json,OpenJPA上的json,Hibernate上的xml,...用于编写通用自定义类型处理程序的JPA2 SPI没有.我正在寻找一个通用的解决方案.
Cra*_*ger 31
问题是PostgreSQL对文本和非文本数据类型之间的强制转换过于严格.它不会允许隐式转换(一个没有CAST或::从文本类型像SQL)text或varchar(character varying)的文本样非文本类型等json,xml等.
PgJDBC驱动程序指定varchar调用setString分配参数时的数据类型.如果列,函数参数等的数据库类型实际上不是,varchar或者是text另一种类型,则会出现类型错误.对于很多其他驱动程序和ORM也是如此.
stringtype=unspecified使用PgJDBC时的最佳选择通常是传递参数stringtype=unspecified.这会覆盖传递setString值的默认行为,varchar而是将其留给数据库以"猜测"其数据类型.在几乎所有情况下,这都完全符合您的要求,将字符串传递给您要存储的类型的输入验证器.
CREATE CAST ... WITH FUNCTION ...您可以改为CREATE CAST定义特定于数据类型的强制类型转换,以便在逐个类型的基础上允许此操作,但这可能会在其他地方产生副作用.如果你这样做,就不能使用WITHOUT FUNCTION强制类型转换,他们将绕过型验证和导致错误.您必须对数据类型使用输入/验证功能.使用CREATE CAST适用于其他数据库驱动程序的用户,这些驱动程序无法停止指定字符串/文本参数类型的驱动程序.
例如
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;
Run Code Online (Sandbox Code Playgroud)
如果您的ORM允许,您可以为数据类型和特定ORM实现自定义类型处理程序.当您使用可以很好地映射到PostgreSQL类型的本机Java类型而不是使用时String,这非常有用,但如果您的ORM允许您使用注释等指定类型处理程序,它也可以工作.
实现自定义类型处理程序的方法是特定于驱动程序,语言和ORM的方法.这是Java和Hibernate的一个例子json.
PGObject如果您在Java中使用本机Java类型,则可以扩展PGObject为您的类型提供PgJDBC类型映射.您可能还需要实现一个特定于ORM的类型处理程序来使用您的PGObject,因为大多数ORM只会调用toString它们无法识别的类型.这是在Java和PostgreSQL之间映射复杂类型的首选方法,也是最复杂的方法.
setObject(int, Object)如果您使用String的是Java中的值,而不是更具体的类型,则可以调用JDBC方法setObject(integer, Object)来存储未指定特定数据类型的字符串.JDBC驱动程序将发送字符串表示形式,数据库将从目标列类型或函数参数类型推断出类型.
问题:
外部: