将空值绑定到准备好的语句时 Postgres bytea 错误

Tim*_*sen 1 postgresql jpa jdbc prepared-statement

我正在使用一个使用 JPA 和 Postgres 数据库的 Java 应用程序,我正在尝试创建一个灵活的准备好的语句,它可以处理可变数量的输入参数。一个示例查询最能解释这一点:

SELECT *
FROM my_table
WHERE
    (string_col = :param1 OR :param1 IS NULL) AND
    (double_col = :param2 OR :param2 IS NULL);
Run Code Online (Sandbox Code Playgroud)

这个“技巧”背后的想法是,如果用户只指定一个参数,比如说:param1,我们可以绑定null:param2,然后该WHERE子句的行为就好像只检查了第一个参数一样。理论上,这种方法让我们可以使用单个准备好的语句处理任意数量的输入参数,而不需要维护许多不同的语句。

我已经使用纯 JDBC 准备好的语句在本地获得了一个简单的 POC。但是,这样做需要在将参数与 比较之前强制转换参数NULL,例如

WHERE (double_col = ? OR ?::numeric IS NULL)
                         ^^ does not work without cast
Run Code Online (Sandbox Code Playgroud)

但是,我的实际应用程序正在使用 JPA,并且我不断收到以下持续错误:

Caused by: org.postgresql.util.PSQLException: ERROR: operator does not exist: double precision = bytea
  Hint: No operator matches the given name and argument type(s). You might need to add explicit type casts.
Run Code Online (Sandbox Code Playgroud)

这个问题不是不能用字符串/文本列发生,但只有它们列double precision在我的Postgres的表。我已经尝试了所有的铸造组合,但没有任何效果:

(double_col = :param2 OR CAST(:param2 AS double precision) IS NULL);
(CAST(double_col AS double precision) = :param2 OR :param2 IS NULL);
(CAST(double_col AS double precision) = :param2 OR CAST(:param2 AS double precision) IS NULL);
Run Code Online (Sandbox Code Playgroud)

该错误似乎是说 JDBC 正在向 Postgres 发送bytea双列的类型,然后 Postgres 正在滚动,因为它找不到转换byte为双精度的方法。

Java 代码如下所示:

Query query = entityManager.createNativeQuery(sqlString, MyEntity.class);
query.setParameter("param1", "some value");
// bind other parameters here
List<MyEntity> = query.getResultList();
Run Code Online (Sandbox Code Playgroud)

作为参考,以下是我正在使用的所有版本:

Hibernate version         | 4.3.7.Final
Spring data JPA vesion    | 1.7.1.RELEASE
Postgres driver version   | 42.2.2
Postgres database version | 9.6.10
Java version              | 1.8.0_171
Run Code Online (Sandbox Code Playgroud)

Tim*_*sen 5

没有收到任何以答案甚至评论形式提供的反馈,当我偶然发现这篇出色的博客文章时,我正准备放弃:

如何将自定义 Hibernate 参数类型绑定到 JPA 查询

该帖子提供了两个选项来控制 JPA 通过驱动程序传递到 Postgres(或任何底层数据库实际上是什么)的类型。我采用了使用TypedParameterValue. 下面是我的代码看起来像继续上面给出的例子:

Query query = entityManager.createNativeQuery(sqlString, MyEntity.class);
query.setParameter("param1", new TypedParameterValue(StringType.INSTANCE, null));
query.setParameter("param2", new TypedParameterValue(DoubleType.INSTANCE, null));
List<MyEntity> = query.getResultList();
Run Code Online (Sandbox Code Playgroud)

当然,null为查询中的每个参数传递是微不足道的,但我这样做主要是为了显示文本和双列的语法。在实践中,我们希望至少有一些参数是 non null,但上面的语法处理所有值,null 或其他。