【问题标题】:QueryDSL and SQL Function from Postgres来自 Postgres 的 QueryDSL 和 SQL 函数
【发布时间】:2017-04-16 23:51:32
【问题描述】:

我想通过 QueryDsl JPA 使用 Postgres 全文搜索。

在 SQL 中生成:

select * 
from film 
where to_tsquery ('tarzan') @@ to_tsvector('french',film.title) = true

获取标题中包含泰山的所有电影。

在 JPA 中,我定义了一个自定义函数“ftsMatch”,我可以像这样使用它:

String jpql = "select film from Film film where ftsMatch(:queryString, film.titre) = true";

我 QueryDSL 我想有机会在字符串类型上定义一个谓词:

QFilm.film.titre.ftsMatch('tarzan')

我没有找到任何解决方案

【问题讨论】:

  • JPQL 允许使用“FUNCTION(funcName, args)”。您不能只是将随机 SQL 函数转储到 JPQL 中,并且必须使用 FUNCTION
  • @Neil:我已经使用自定义方言通过 JPQL 解决了 pb,并在实现 org.hibernate.dialect.function.SQLFunction 的类中实现了该函数。问题是如何用 QueryDSL 解决同样的问题?
  • 如前所述,不需要 JPA 专有解决方案(自定义方言),因为“FUNCTION”是 JPA 2.1 标准。而且由于 QueryDSL 应该在内部创建 JPQL,所以它应该有一个 FUNCTION 方法

标签: postgresql jpa querydsl


【解决方案1】:

我想做的是扩展 com.querydsl.core.types.dsl.StringExpression.class 并添加一个自定义函数 fullTextMatch() 可以像这样使用:

BooleanBuilder booleanBuilder = new BooleanBuilder(QFilm.film.titre.fullTextMatch(_titre, "french"));

它会变成 SQL :

select film0_.id as id1_2_ .. from film film0_ 
where  to_tsquery (?) @@   to_tsvector('pg_catalog.french',film0_.titre)=true

上面的QueryDSL语法我还没找到怎么获取,但是找到了如下解决方案:

1/ 为 Postgres 定义自定义方言 并在此方言上注册 Customm 功能:

public class CustomFullTextPostgresDialect extends PostgreSQL94Dialect {

    public CustomFullTextPostgresDialect() {
        registerFunction("ftsMatch", new PostgreSQLFullTextSearchFunction());
    }

}

2/ 编写自定义函数PostgreSQLFullTextSearchFunction实现org.hibernate.dialect.function.SQLFunction 这个函数 'ftsMacth' 将生成 SQL:

String fragment = " to_tsquery (" + value + ") @@   to_tsvector(" + ftsConfig + "," + field + ")";

这一步让我可以访问 JPA 中的 Posgres FullText:

String jpql = "select film from Film film "
        + "where FUNCTION( 'ftsMatch', :titre,'pg_catalog.french', film.titre) = true";
TypedQuery<Film> typedQuery = em.createQuery(jpql, Film.class);
typedQuery.setParameter("titre", _titre);
List<Film> list = typedQuery.getResultList();

3/使用QueryDsl中继到扩展的postgres方言上定义的自定义函数:

BooleanTemplate predicate = Expressions
        .booleanTemplate("FUNCTION('ftsMatch', {0},'pg_catalog.french', film.titre) = true ", _titre);

Page<Film> page = filmRepository.findAll(predicate, _pageable);

但是使用这个 QueryDSL 解决方案,我仍然需要 Hibernate 自定义。而且语法不再是面向 DSL 的

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-05-31
    • 1970-01-01
    • 1970-01-01
    • 2021-04-11
    • 2021-06-05
    • 1970-01-01
    • 2015-08-28
    相关资源
    最近更新 更多