在JPA CriteriaBuilder中使用正则表达式

时间:2014-07-28 13:01:32

标签: java mysql regex hibernate jpa

我使用JPA CriteriaBuilder从MySQL数据库中选择MyEntity类型的实体,如下所示:

String regExp = "(abc|def)"
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery query = cb.createQuery( MyEntity.class );
root = query.from( MyEntity.class );
predicates = new ArrayList<Predicate>();

predicates.add( cb.like( root.<String>get( "name" ), regExp ) );

因此,查询结果应包含name值与给定regExp匹配的任何实体。但结果列表始终为空。 将regExp更改为/(abc|def)/g无效,也不会添加通配符%

如何使模式匹配起作用?

或者:我如何将本机MySQL REGEXP与CriteriaBuilder一起使用?

3 个答案:

答案 0 :(得分:3)

JPA查询中的模式匹配仅限于

  • _ - 任何角色
  • % - 任意字符串

REGEXP在MySQL中具有运算符语法(SELECT 'a' REGEXP 'A'),因此无法与CriteriaBuilder.function() API一起使用。我担心最好是运行本机SQL查询。

如果你正在使用Hibernate,你还有一个选择。您可以wrap REGEXP operator in SQLFunctionTemplate, extend hibernate dialect使用CriteriaBuilder.function()运行。

答案 1 :(得分:1)

也许这段代码会有所帮助。我们必须在搜索中排除字符,我们使用Oracle。 CriteriaBuilder(至少从2.1开始)将允许您调用函数。

private static final Pattern UNDESIRABLES = Pattern.compile("[(){},.;!?<>%_-]");
private static final String UNDESIRABLE_REPLACEMENT = "";
...

在搜索方法中,创建要在where子句中使用的谓词:

Expression<String> undesirables = cb.literal(UNDESIRABLES.toString());
Expression<String> replaceWith = cb.literal(UNDESIRABLE_REPLACEMENT);
Expression<String> regExp = cb.function("REGEXP_REPLACE", String.class, client.get(Client_.companyName),
    undesirables, replaceWith);
Predicate companyNameMatch = cb.equal(cb.trim(cb.lower(regExp)), removeUndesireables(name).trim());
...

为右手comapare创建一个使用与左边相同的值的方法:

private String removeUndesireables(String name) {
    return UNDESIRABLES.matcher(name).replaceAll(UNDESIRABLE_REPLACEMENT).toLowerCase();
}

答案 2 :(得分:1)

我最近遇到过这个并使用第一篇文章来实现hibernate mysql函数选项。

为了帮助我节省一些时间,这就是我所做的:

在hibernate中设置自定义方言文件中的函数:

public class MySQLDialect extends Dialect {

   public MySQLDialect() {
      super();
      ...
      registerFunction("regexp", new SQLFunctionTemplate(StandardBasicTypes.INTEGER, "?1 REGEXP ?2"));
      ...
   }
   ...
}

然后 在标准构建器部分中:

CriteriaBuilder builder = ...;    

Pattern regexPattern = Pattern.compile("^[0-9]\\|[0-9]+");

Expression<String> patternExpression = builder.<String>literal(regexPattern.pattern());

Path<String> path = ... ;// regex comparison column

// regexp comes from the name of the regex function 
// defined in the Mysql Dialect file above
Predicate theRegexPredicate = builder.equal(builder.function("regexp", Integer.class, path, patternExpression), 1);

然后使用theRegexPredicate在CriteriaBuilder查询中构造where子句。