我尝试使用 Criteria 调用 Postgres 函数,但它不起作用。我需要在 UUID 字段中使用
LIKE
子句,因此我需要先转换为 VARCHAR
。
我需要的结果:
SELECT * FROM my_table WHERE cast(uuid as varchar(36)) like '%1234%';
我在标准中做什么:
final Path<UUID> uuidField = from.get("uuid");
var cast = cb.function("cast", String.class, uuidField, cb.literal("as varchar(36)"));
cb.like(cast, String.format("%%%s%%", stringValue));
正在生成的查询:
HQL: select generatedAlias0 from com.MyTable as generatedAlias0 where function('cast', generatedAlias0.uuid, 'as varchar(36)') like '%1234%' order by generatedAlias0.name asc
错误:
2022-08-08 18:38:48,549 WARN [io.ver.cor.imp.BlockedThreadChecker] (vertx-blocked-thread-checker) Thread Thread[vert.x-eventloop-thread-9,5,main] has been blocked for 2393 ms, time limit is 2000 ms: io.vertx.core.VertxException: Thread blocked
at antlr.ASTFactory.make(ASTFactory.java:342)
at antlr.ASTFactory.make(ASTFactory.java:352)
at org.hibernate.hql.internal.antlr.HqlBaseParser.jpaFunctionSyntax(HqlBaseParser.java:4633)
at org.hibernate.hql.internal.antlr.HqlBaseParser.primaryExpression(HqlBaseParser.java:1075)
日志不太清楚(我使用的是 Quarkus + Hibernate Reactive),但我怀疑它在数据库中崩溃了,因为
function('cast', generatedAlias0.uuid, 'as varchar(36)')
。
我认为应该是这样的:
function('cast', generatedAlias0.uuid, as varchar(36))
(不带引号)。但我不知道如何获得这个结果来检验我的理论。
如何调用这个
CAST
函数?
在研究了一些可能的解决方案(我避免创建自定义数据库例程)之后,我在另一个问题的答案中发现了一些有趣的东西:
目前JPA没有replace()和cast(string as numeric)的API。但如果数据库可移植性不重要,您可以使用 CriteriaBuilder.function(...) 创建数据库本机函数。
来源:JPA 标准生成器:如何按顺序替换字符串并将其转换为数字?
我不知道这是否记录在某个地方,但假设无法使用 Criteria 调用
CAST(x AS y)
,我尝试了一种解决方法来强制 UUID
到 VARCHAR
转换,而不使用可能不受支持的 CAST
功能。
我测试了对数据库的直接 SQL 查询:
SELECT * FROM my_table WHERE concat(uuid, '') like '%123%';
而且它有效。这个
CONCAT
强制转换为 VARCHAR
并且 LIKE
函数完成了他的工作。知道这一点后,我做到了:
final Path<UUID> uuidField = from.get("uuid");
var cast = cb.function("concat", String.class, uuidField, cb.literal(""));
cb.like(cast, String.format("%%%s%%", stringValue));
工作完美。我希望这对其他人有帮助。
正如@HaroldH所说,这是一个奇怪的要求,但发生在我的项目中。
您必须使用“.as()”JPA 函数,以便本机调用“cast”。
即您的用例:
cb.like(from.get("uuid").as(String.class), String.format("%%%s%%", stringValue));