Priidu Neemre
Priidu Neemre

Reputation: 3071

Spring Data JPA - case insensitive query w/ pattern matching

Suppose I'm implementing search functionality for a simple CMS package (just an example), and want to match posts by both their title and content. Presumably, I would have some sort of Post entity with the following underlying table structure:

+------------------------------------+
|               POST                 |
+---------+--------------+-----------+
| post_id | INTEGER      | NOT NULL, |
| title   | VARCHAR(255) | NOT NULL, |
| content | CLOB         | NOT NULL  |
+---------+--------------+-----------+

Next, I would extend Spring's JpaRepository and add the search method via @Query annotation, like so (again, just an example):

public interface PostRepository extends JpaRepository<Post, Integer> {

    @Query("SELECT p FROM Post AS p WHERE lower(p.title) LIKE lower(%:searchTerm%)"  
            + " OR lower(p.content) LIKE lower(%:searchTerm%) ORDER BY p.title")
    List<Post> findBySearchTerm(@Param("searchTerm") String searchTerm);
}

The problem is that Spring (or maybe it's just the underlying JPA provider, not sure) has a hard time parsing this query due to the lower(%:searchTerm%) expression in the WHERE clause. I've also tried other variations of this syntax, e.g. %lower(:searchTerm)%, but none seem to work so far. Does anybody have a good (and preferably clean) solution for this?

P.S.: I would prefer to use the @Query annotation for consistency's sake. However, I guess other solutions (such as Spring's method name -> query derivation or the Criteria API) are also welcome.

Upvotes: 0

Views: 10979

Answers (2)

Dale
Dale

Reputation: 1626

Try something like this:

@Query("SELECT u.username FROM User u WHERE u.username LIKE     
lower(CONCAT('%',:username,'%')"))
List<String> findUsersWithPartOfName(@Param("username") String username);

Notice: The table name in JPQL must start with a capital letter.

Upvotes: 3

sura2k
sura2k

Reputation: 7517

1) Inject searchTerm already in lower case to the method, and use JPQL ..... lower(COLUMN_NAME) like %:searchTerm%

2) Use method names with following naming syntax, so you don't need to provide % to the JPQL ..... lower(COLUMN_NAME) :searchTerm

findBySearchTermContainingIgnoreCase(String searchTerm)
findBySearchTermStartingWithIgnoreCase(String searchTerm)

Upvotes: 4

Related Questions