简体   繁体   中英

Case-insensitive search using Hibernate

I'm using Hibernate for ORM of my Java app to an Oracle database (not that the database vendor matters, we may switch to another database one day), and I want to retrieve objects from the database according to user-provided strings. For example, when searching for people, if the user is looking for people who live in 'fran', I want to be able to give her people in San Francisco.

SQL is not my strong suit, and I prefer Hibernate's Criteria building code to hard-coded strings as it is. Can anyone point me in the right direction about how to do this in code, and if impossible, how the hard-coded SQL should look like?

Thanks,

Yuval =8-)

For the simple case you describe, look at Restrictions.ilike(), which does a case-insensitive search.

Criteria crit = session.createCriteria(Person.class);
crit.add(Restrictions.ilike('town', '%fran%');
List results = crit.list();
Criteria crit = session.createCriteria(Person.class);
crit.add(Restrictions.ilike('town', 'fran', MatchMode.ANYWHERE);
List results = crit.list();

如果你使用Spring的HibernateTemplate与Hibernate进行交互,那么你可以在这里对用户的电子邮件地址进行不区分大小写的搜索:

getHibernateTemplate().find("from User where upper(email)=?", emailAddr.toUpperCase());

The usual approach to ignoring case is to convert both the database values and the input value to upper or lower case - the resultant sql would have something like

select f.name from f where TO_UPPER(f.name) like '%FRAN%'

In hibernate criteria restrictions.like(...).ignoreCase()

I'm more familiar with Nhibernate so the syntax might not be 100% accurate

for some more info see pro hibernate 3 extract and hibernate docs 15.2. Narrowing the result set

You also do not have to put in the '%' wildcards. You can pass MatchMode ( docs for previous releases here ) in to tell the search how to behave. START , ANYWHERE , EXACT , and END matches are the options.

Since Hibernate 5.2 session.createCriteria is deprecated. Below is solution using JPA 2 CriteriaBuilder. It uses like and upper :

    CriteriaBuilder builder = session.getCriteriaBuilder();
    CriteriaQuery<Person> criteria = builder.createQuery(Person.class);
    Root<Person> root = criteria.from(Person.class);

    Expression<String> upper = builder.upper(root.get("town"));
    criteria.where(builder.like(upper, "%FRAN%"));

    session.createQuery(criteria.select(root)).getResultList();

大多数默认数据库排序规则不区分大小写,但在SQL Server环境中,可以在实例,数据库和列级别设置它。

You could look at using Compass a wrapper above lucene.

http://www.compass-project.org/

By adding a few annotations to your domain objects you get achieve this kind of thing.

Compass provides a simple API for working with Lucene. If you know how to use an ORM, then you will feel right at home with Compass with simple operations for save, and delete & query.

From the site itself. "Building on top of Lucene, Compass simplifies common usage patterns of Lucene such as google-style search, index updates as well as more advanced concepts such as caching and index sharding (sub indexes). Compass also uses built in optimizations for concurrent commits and merges."

I have used this in the past and I find it great.

This can also be done using the criterion Example, in the org.hibernate.criterion package.

public List findLike(Object entity, MatchMode matchMode) {
    Example example = Example.create(entity);
    example.enableLike(matchMode);
    example.ignoreCase();
    return getSession().createCriteria(entity.getClass()).add(
            example).list();
}

Just another way that I find useful to accomplish the above.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM