【问题标题】:Hibernate Criteria Query to use MySQL REPLACE and CONCAT functionsHibernate Criteria Query 使用 MySQL REPLACE 和 CONCAT 函数
【发布时间】:2019-09-12 08:33:36
【问题描述】:

尝试使用CriteriaBuilder 在 Hibernate 中复制以下 MySQL 查询。此查询添加名字和姓氏,删除中间的所有空格并搜索与给定字符串匹配的结果。

select * from users where replace(concat(first_name, last_name), " ", "") like 'jamesbon%';

final CriteriaBuilder criteriaBuilder = getCurrentSession().getCriteriaBuilder();
final CriteriaQuery<UserImpl> userCriteriaQuery = criteriaBuilder.createQuery(UserImpl.class);

final Root<UserImpl> userRoot = userCriteriaQuery.from(UserImpl.class);

// criteriaBuilder.concat(userRoot .get("firstName"), userRoot .get("lastName"))

【问题讨论】:

    标签: mysql hibernate jpa hibernate-criteria


    【解决方案1】:

    Concat 可通过构建器获得,因此您真正需要添加的只是 replace 函数。

    您需要做的是创建一个实现org.hibernate.boot.spi.MetadataBuilderInitializer 的类,并使用它向Hibernate 注册函数。假设您的班级名为com.project.hibernate.MetaContrib

    package com.project.hibernate;
    
    import org.hibernate.boot.MetadataBuilder;
    import org.hibernate.boot.registry.StandardServiceRegistry;
    import org.hibernate.boot.spi.MetadataBuilderInitializer;
    import org.hibernate.dialect.function.StandardSQLFunction;
    import org.hibernate.type.StringType;
    
    public class MetaContrib implements MetadataBuilderInitializer {
    
        @Override
        public void contribute(MetadataBuilder metadataBuilder, StandardServiceRegistry serviceRegistry) {
            metadataBuilder.applySqlFunction("str_replace", new StandardSQLFunction("replace", StringType.INSTANCE));
            metadataBuilder.applySqlFunction("regex_replace", new StandardSQLFunction("REGEXP_REPLACE", StringType.INSTANCE));
        }
    
    }
    

    下一步是告诉 Hibernate 加载它,方法是在资源的 META-INF/services 目录中创建一个名为 org.hibernate.boot.spi.MetadataBuilderInitializer 的文件。如果这样的目录不存在,请创建它。该文件必须包含实现类的全名,并以新行结尾。

    终于用上了:

    expr1 = criteriaBuilder.concat(userRoot.get("firstName"), userRoot.get("lastName"));
    expr2 = criteriaBuilder.function("str_replace", String.class, expr1, " ", "");
    expr3 = criteriaBuilder.like(expr2, cb.parameter(String.class, "sv"));
    userCriteriaQuery.where(expr3)
    
    return createQuery(userCriteriaQuery)
               .setParameter("sv", "jamesbon%")
               .getResultList();
    

    详细解释:

    CriteriaBuilder 创建一个 JPQL 查询。你的函数表达式变成这样:

    ... WHERE function('str_replace', concat(u.firstName, u.lastName), ' ', '') LIKE :sv
    

    呈现给本机查询时的样子:

    where replace(concat(u0.first_name, u0.last_name), ' ', '') like :sv
    

    该函数在 JPQL 中以名称 str_replace 注册,但它可以是您选择的任何名称。这是你给 StandardSQLFunction 构造函数的名称,它告诉它本机名称是什么。

    然后再往下,:sv 内部变为?,当您使用 setParameter 时,它会告诉 JDBC 驱动程序在该位置安全地发送字符串。

    但是,如果您想删除所有空格,而不仅仅是所有 0x20 空格字符,您应该使用像 \s+ 这样的正则表达式以及我在 MetaContrib 中输入的另一个函数。只有当您的 MySQL 是 8.0.4 或更高版本,或者 MariaDB 10.0.8 或更高版本时,您才能这样做。该函数存在于 MariaDB10Dialect 中,因此如果您使用 MariaDB,则可能不需要 MetaContrib 类。

    【讨论】:

    • 此外,从 Hibernate ORM 版本 5.2.18 和 5.3.1 开始,如果您有多个持久性单元,您可以将函数贡献为每个配置,而不是全局,但它是使用不同的班级。见HHH-12589。奇怪的是 5.2.18 发布了,但从未公布。甚至他们的网站仍然说 5.2 中的最新版本是 17。
    • 你太棒了 :) 感谢您抽出宝贵的时间来写这个详细的答案。
    • @VijayNandwana 我刚刚编辑了正则表达式,因为我记得 w 是单词,而不是空格。
    猜你喜欢
    • 2015-11-18
    • 2021-07-03
    • 2013-05-27
    • 1970-01-01
    • 2011-05-11
    • 2014-10-03
    • 2013-03-13
    • 2017-07-17
    • 1970-01-01
    相关资源
    最近更新 更多