Reputation: 1523
I'm using the JPA CriteriaBuilder to select entities of type MyEntity
from a MySQL db as follows:
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 ) );
Thus, the query result should contain any entity where the name
value matches the given regExp. But the result list is always empty.
Changing the regExp to /(abc|def)/g
has no effect, neither does adding the wildcard %
How to make the pattern matching work?
Alternatively: How can I use native MySQL REGEXP together with the CriteriaBuilder?
Upvotes: 12
Views: 25109
Reputation: 351
If you are using Postgres you can combine array_length and regexp_match functions, by invoking criteriaBuilder.function() to generate sql like this:
... where array_length(regexp_match(my_field,'<my_regexp_pattern>'),1)>0
the > 0 condition checks if there is a match for the my_regexp_pattern. If you want to verify that my_regexp_pattern does not match use:
regexp_match(my_field,'<my_regexp_pattern>') is null
Upvotes: 0
Reputation: 1844
I came across this recently and used the first post to implement the hibernate mysql function option.
To help save some time for others this is what I did:
set up the function in your custom dialect file in hibernate:
public class MySQLDialect extends Dialect {
public MySQLDialect() {
super();
...
registerFunction("regexp", new SQLFunctionTemplate(StandardBasicTypes.INTEGER, "?1 REGEXP ?2"));
...
}
...
}
then within the criteria builder section:
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);
Then use theRegexPredicate to construct the where clause in your CriteriaBuilder query.
Upvotes: 5
Reputation: 4038
Maybe this snippet will help. We had to exclude characters in a search, and we using Oracle. CriteriaBuilder (at least as of 2.1) will let you call a function.
private static final Pattern UNDESIRABLES = Pattern.compile("[(){},.;!?<>%_-]");
private static final String UNDESIRABLE_REPLACEMENT = "";
...
In the search method, create a Predicate to use in your where clause:
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());
...
And create a method for the right hand comapare that uses the same values as the left:
private String removeUndesireables(String name) {
return UNDESIRABLES.matcher(name).replaceAll(UNDESIRABLE_REPLACEMENT).toLowerCase();
}
Upvotes: 2
Reputation: 3956
Pattern matching in JPA queries is limited only to
_
- any character%
- any stringREGEXP
has operator syntax in MySQL (SELECT 'a' REGEXP 'A'
) so it cannot be used with CriteriaBuilder.function()
API. I'm afraid the best is to run native SQL query.
If you are using Hibernate you have one more option. You can wrap REGEXP
operator in SQLFunctionTemplate
, extend hibernate dialect and run with CriteriaBuilder.function()
.
Upvotes: 9