Java JPA标准API中订单的自定义SQL

Java JPA标准API中订单的自定义SQL,java,hibernate,jpa,hibernate-criteria,criteria-api,Java,Hibernate,Jpa,Hibernate Criteria,Criteria Api,我正在从不推荐的(不幸的)Hibernate标准API切换到JPA标准API。我们有一个自定义的Order(来自Hibernate)接口实现来重新定义为它生成的SQL。这种情况非常复杂,因为我们需要在子查询中使用一个巨大的SELECT。我们实现了接口的toSqlString方法来返回这个巨大的SQL,我们需要一种方法将它迁移到JPA标准API 问题是:JPA CriteriaAPI中是否有方法重新定义生成的SQL?还是有一种奇怪的方式将Hibernate Order与JPA Criteria A

我正在从不推荐的(不幸的)Hibernate标准API切换到JPA标准API。我们有一个自定义的Order(来自Hibernate)接口实现来重新定义为它生成的SQL。这种情况非常复杂,因为我们需要在子查询中使用一个巨大的SELECT。我们实现了接口的
toSqlString
方法来返回这个巨大的SQL,我们需要一种方法将它迁移到
JPA标准API

问题是:JPA CriteriaAPI中是否有方法重新定义生成的SQL?还是有一种奇怪的方式将Hibernate Order与JPA Criteria API一起使用

谢谢大家!


更新尽管@Tobias Liefke的建议非常有趣,但我的SQL变化太大,无法为每个SQL创建函数类。我尝试实现一个函数类,并将SQL作为参数传递到那里,但没有成功(呈现的SQL包含在单引号中,因此它作为参数发送到数据库,而不是作为生成的查询的一部分)

您不能在JPQL或条件查询中使用SQL片段

。。。除非

1.调用函数 JPA和Hibernate允许在其表达式中使用函数,例如:

... ORDER BY trim(entity.label) ASC
分别

问题是,这实际上不是对SQL函数
trim
的调用,而是对JPA函数的调用,必须注册该函数(Hibernate已经对最常见的SQL函数进行了注册)

幸运的是,您可以在
方言解析器中定义自己的JPA函数:

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:

并将其登记为:

dialect.registerFunction("myOrderFunction",  new MyOrderFunction());
此解决方案的另一个优点是:可以根据实际的数据库方言定义不同的SQL

2.使用公式 您可以为实体使用其他属性:

@Formula("my huge SQL")
private String orderAttribute;
现在可以按此属性进行排序:

... ORDER BY entity.orderAttribute ASC
分别

我只推荐这种解决方案,如果您需要模型中庞大SQL的结果。否则,它只会污染实体模型,并将SQL添加到实体的每个查询中(除非您使用
@Basic(fetch=FetchType.lazy)
标记它并使用字节码检测)


类似的解决方案是使用巨大的SQL定义一个
@Subselect
实体,但也有同样的缺点。

非常有趣,非常感谢!因此,我可以使用第一个解决方案,而不必在Oracle中创建实际的函数,也不必简单地实现SQLFunction接口,对吗?对。事实上,第一个解决方案包含两个“风格”:一个带有自定义SQL函数,另一个带有映射接口。太棒了!很好的解决方案,我想,在这种情况下是最好的:)这种方法似乎不起作用。最终,函数返回SQL,但它会像通常的字符串一样被括在括号中。甚至Hibernate也将其类型显示为VARCHAR。有没有办法将函数呈现为SQL而不是字符串?您指的是哪种括号?字符串通常用单引号(
)括起来,而不是用括号括起来。我自己实现了不止一个
SQLFunction
,并且确信Hibernate通常不会添加引号或括号。
dialect.registerFunction("myOrderFunction",  new MyOrderFunction());
@Formula("my huge SQL")
private String orderAttribute;
... ORDER BY entity.orderAttribute ASC
query.orderBy(criteriaBuilder.asc(root.get(ExampleEntity_.orderAttribute))));