java - JPA Criteria API 中订单的自定义 SQL
问题描述
我正在从已弃用的(不幸的是)Hibernate Criteria API 切换到 JPA Criteria API。我们有一个自定义的 Order(来自 Hibernate)接口实现来重新定义为其生成的 SQL。这个案例非常复杂,因为我们需要使用带有子查询的巨大SELECT。我们实现toSqlString
了接口的方法来返回这个巨大的 SQL,我们需要一种方法将它迁移到JPA Criteria API
.
问题是:JPA Criteria API 中有没有办法重新定义生成的 SQL?或者有没有一种奇怪的方式来使用 Hibernate Order 和 JPA Criteria API?
谢谢!
更新虽然@Tobias Liefke 的建议很有趣,但我的 SQL 变化太大,无法为每个 SQL 创建一个函数类。我尝试实现一个函数类并将 SQL 作为参数传递给那里,但这不起作用(呈现的 SQL 用单引号括起来,因此它作为参数而不是作为生成查询的一部分发送到数据库)
解决方案
您不能在 JPQL 或条件查询中使用 SQL 片段...
... 除非...
1.调用函数
JPA 和 Hibernate 允许在其表达式中使用函数,例如:
... ORDER BY trim(entity.label) ASC
响应。
query.orderBy(criteriaBuilder.asc(
criteriaBuilder.function("trim", String.class, root.get(ExampleEntity_.label))));
问题是,这实际上不是对 SQL 函数trim
的调用,而是对 JPA 函数的调用,它必须被注册(Hibernate 已经为最常见的 SQL 函数这样做了)。
幸运的是,您可以在 a 中定义自己的 JPA 函数DialectResolver
:
public class MyDialectResolver implements DialectResolver {
public Dialect resolveDialect(final DialectResolutionInfo info) {
Dialect dialect = StandardDialectResolver.INSTANCE.resolve(info);
dialect.registerFunction("myOrderFunction", ...);
return dialect;
}
}
registerFunction
有两个参数,第一个是JPA中的函数名,另一个是到SQL的映射。
不要忘记在你的声明你的方言解析器persistence.xml
:
<persistence-unit name="database">
<properties>
<property name="hibernate.dialect_resolvers"
value="my.package.MyDialectResolver" />
</properties>
</persistence-unit>
你现在可以在你的 SQL 服务器中创建你自己的函数,它包含你巨大的 SQL并将其注册为函数:
dialect.registerFunction("myOrderFunction",
new StandardSQLFunction("myOrderFunctionInSQL", StringType.INSTANCE));
或者您可以编写自己的映射,其中包括您庞大的 SQL:
public class MyOrderFunction implements SQLFunction {
public String render((Type firstArgumentType, List arguments,
SessionFactoryImplementor factory) throws QueryException) {
return my_huge_SQL;
}
// ...
}
并注册那个:
dialect.registerFunction("myOrderFunction", new MyOrderFunction());
此解决方案的另一个优点:您可以根据实际的数据库方言定义不同的 SQL。
2. 使用公式
您可以为您的实体使用附加属性:
@Formula("my huge SQL")
private String orderAttribute;
您现在可以按此属性排序:
... ORDER BY entity.orderAttribute ASC
响应。
query.orderBy(criteriaBuilder.asc(root.get(ExampleEntity_.orderAttribute))));
我只推荐这个解决方案,如果你仍然需要模型中庞大的 SQL的结果。否则,它只会污染您的实体模型并将 SQL 添加到您的实体的每个查询中(除非您使用字节码检测@Basic(fetch = FetchType.lazy)
标记它并使用它)。
一个类似的解决方案是@Subselect
使用巨大的 SQL 定义一个实体 - 具有相同的缺点。
推荐阅读
- laravel - 使用 Woocommerce REST API“自动/woocommerce”上传图像时“抱歉,出于安全原因,不允许使用此文件类型”
- php - 如何在给定的特定时间运行 php 脚本而不使用 cron 作业和打开网页?
- java - 线程在调用方法之后但在方法的第一条指令之前会失去控制吗?
- java - Java Kafka Consumer 处理二进制图像数据
- jscript - 从 wsh 脚本获取响应
- r - 将文本文件读取为格式化列表
- angular - Jasmine,如何测试可观察的方法逻辑?
- javascript - 找不到变量:firebase
- c - 如何在 C 中处理 TCP 客户端断开连接
- python-3.x - pandas style.applymap 不适用于大型数据集