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