Java 如何使用本机SQL作为Hibernate中使用CriteriaAPI进行的更大查询的片段(where子句)?

Java 如何使用本机SQL作为Hibernate中使用CriteriaAPI进行的更大查询的片段(where子句)?,java,sql,hibernate,jpa,criteria-api,Java,Sql,Hibernate,Jpa,Criteria Api,我有以下问题。在我正在开发的应用程序中,我们使用Hibernate,每个查询都使用CriteriaAPI编写。现在,在某些地方,我们希望为用户添加编写一些SQL代码的可能性,这些代码将用作查询中where子句的一部分。所以基本上,用户可以用自己的方式从数据库中过滤显示给他的数据 几天来,我一直在试图找到一种方法来修改我们以前的查询,以获得上面描述的结果。以下是我所知道的: 看起来您无法将标准API与本机SQL结合起来。您可以用SQL编写整个查询,也可以只使用CriteriaAPI。是这样吗? 我

我有以下问题。在我正在开发的应用程序中,我们使用Hibernate,每个查询都使用CriteriaAPI编写。现在,在某些地方,我们希望为用户添加编写一些SQL代码的可能性,这些代码将用作查询中where子句的一部分。所以基本上,用户可以用自己的方式从数据库中过滤显示给他的数据

几天来,我一直在试图找到一种方法来修改我们以前的查询,以获得上面描述的结果。以下是我所知道的:

  • 看起来您无法将标准API与本机SQL结合起来。您可以用SQL编写整个查询,也可以只使用CriteriaAPI。是这样吗? 我问这个问题是因为这将是最简单的解决方案,只需将此SQL代码用作查询中where子句中的另一个谓词即可。但我认为在这个层面上是不可能的

  • 我知道用户要在哪个表上过滤数据。所以我可以只执行本机SQL查询,并使用结果列表作为条件查询中IN子句的参数。但我不知道如果结果列表中有很多记录,它是否有效

  • 因此,如果我不能在CriteriaAPI级别上实现这一点,我想也许我可以以某种方式影响SQL生成过程,并将我的SQL放在适当的位置,但这似乎是不可能的

  • 所以我真正的问题是:在SQL生成阶段之后,但在实际执行查询之前,是否有可能访问查询的SQL代码?只是为了手动操作?是否可以安全且尽可能简单地完成

  • 或者只是尝试解析用户编写的SQL并在条件查询中使用它


  • 将现有条件查询更改为本机SQL查询是不需要讨论的。

    是的,您可以使用
    org.Hibernate.loader.CriteriaQueryTranslator
    类从Hibernate条件获取SQL

    这将允许您将附加的SQL子句附加到末尾,并将其作为本机SQL执行:

    CriteriaQueryTranslator translator = new CriteriaQueryTranslator(factory, criteria, "myEntityName", CriteriaQueryTranslator.ROOT_SQL_ALIAS);
    String select = translator.getSelect();    
    String whereClause = translator.getWhereCondition();
    
    但就我个人而言,如果面临这个需求,我会避免接受来自最终用户的SQL,并给他们一个用户界面来填充某种类型的过滤器对象。然后,可以将其转换为HQL标准,它更安全,并且不会将代码与数据库实现紧密地联系在一起

    根据评论进行编辑

    从使用Hibernate实现的JPA查询中提取SQL的示例:

    CriteriaBuilder builder = entityManager.getCriteriaBuilder();
    CriteriaQuery<MyEntity> q = builder.createQuery(MyEntity.class);
    Root<MyEntity> entity = q.from(MyEntity.class);
    q.select(entity).orderBy(builder.desc(entity.get("lastModified")));
    TypedQuery<MyEntity> query = entityManager.createQuery(q);
    
    String sql = query.unwrap(org.hibernate.Query.class).getQueryString();
    
    CriteriaBuilder=entityManager.getCriteriaBuilder();
    CriteriaQuery q=builder.createQuery(MyEntity.class);
    根实体=q.from(MyEntity.class);
    q、 选择(实体).orderBy(builder.desc(实体.get(“lastModified”));
    TypedQuery=entityManager.createQuery(q);
    字符串sql=query.unwrap(org.hibernate.query.class).getQueryString();
    
    No,不能将SQL与JPA标准一起使用-JPA标准用于编写JPQL。如果某些实现“提供”它作为扩展,那么您将失去可移植性。根据JPA Spect感谢您的回答,我将尝试在片刻内执行您的建议。我同意你关于接受终端用户SQL的建议,我也考虑过另一个解决方案,但我们正在尝试的是开发一个新的、更好的应用程序,它具有与现有应用程序相同的功能,并且需要向后兼容。换句话说,已经用SQL编写的过滤器应该也能在我们的应用程序中使用。嗯,很抱歉没有做到精确甚至错误,但这对我来说是全新的。我们使用hibernate JPA实现而不是hibernate标准API创建查询。您上面编写的代码示例似乎只适用于Hibernate标准API,对吗?或者我只是混淆了概念?抱歉,我误解了你的问题。JPA规范中似乎没有要求查询公开底层SQL(这很有意义)。您可能需要继续讨论实现,我将用一个示例更新我的答案。我已经尝试了您的建议(编辑的部分),但我担心这仍然不是我需要的。它正在工作,我得到一个查询字符串,我可以编辑它并进行另一个查询(我必须记住从第一个查询复制参数),但我得到的字符串看起来像HQL而不是SQL。SQL生成将在稍后进行-在我的例子中,是在执行“query.getResultList()”期间。我需要做的是进入Hibernate的内部方法中间,并适当地改变一些东西。我不知道这是否可能。我确信(尽管目前没有办法尝试!)上述方法的组合应该可以达到您的要求。JPA查询是在Hibernate中使用Hibernate标准API实现的,只是隐藏在JPA接口后面。如果您能够强制转换或展开JPA查询对象,您应该可以访问CriteriaQueryTranslator类的功能。祝你好运