首页 文章

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

提问于
浏览
7

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

几天后,我试图找到一种方法来修改我们之前的查询以获取上述结果 . 这就是我所知道的:

  • 看起来您无法将Criteria API与本机SQL结合使用 . 您可以在SQL中编写整个查询,也可以仅使用条件API . 是对的吗?我问这个问题是因为这是最简单的解决方案,只是将这个SQL代码用作查询中where子句的另一个谓词 . 但我认为这不可能达到这个水平 .

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

  • 因此,如果我无法在标准API级别上执行此操作,我认为也许我可以以某种方式影响SQL生成过程并将我的SQL放在适当的位置,但这似乎是不可能的 .

  • 所以我真正的问题是: is it somehow possible to have access to SQL code of the query, after SQL generation phase but before actual execution of query? 只是手动操作它?它可以安全地尽可能简单地完成吗?

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

将现有条件查询更改为本机SQL查询相当于讨论 .

1 回答

  • 3

    是的,您可以使用 org.hibernate.loader.criteria.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标准,这样更安全,并且不会将您的代码紧密地绑定到数据库实现 .

    Edit based on comments

    从使用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();
    

相关问题