子串搜索JPA / Hibernate的数字字段

时间:2016-11-18 19:06:07

标签: sql hibernate jpa hql

我有一个具有数字字段的JPA实体。类似的东西:

@Basic(optional = false)
@Column(name = "FISCAL_YEAR", nullable = false)
private int fiscalYear;

我要求子字符串搜索此字段。例如,我想要搜索17,以便为我20171917以及1789。暂时忘记这是一个疯狂的请求,并假设我有一个真正有用的用例。无法选择将列更改为数据库中的varchar。

在PL / SQL中,我将字段转换为varchar并执行like '%17%'。如何在不使用本机查询的情况下使用Hibernate / JPA实现此目的?我需要能够使用HQL或Criteria来做同样的事情。

2 个答案:

答案 0 :(得分:1)

使用条件构建器

在数值上实现

表格

Employee | CREATE TABLE `Employee` (
`id` int(11) NOT NULL,
`first` varchar(255) DEFAULT NULL,
`last` varchar(255) DEFAULT NULL,
`occupation` varchar(255) DEFAULT NULL,
`year` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

<强>实体

private Integer year;
public Integer getYear() {
    return year;
}
public void setYear(Integer year) {
    this.year = year;
}

表格中的数据

+----+-------+------+------------+------+
| id | first | last | occupation | year |
+----+-------+------+------------+------+
|  2 | Ravi  | Raj  | Textile    | 1718 |
|  3 | Ravi  | Raj  | Textile    | 1818 |
|  4 | Ravi  | Raj  | Textile    | 1917 |
|  5 | Ravi  | Raj  | Textile    | NULL |
|  6 | Ravi  | Raj  | Textile    | NULL |
|  7 | Ravi  | Raj  | Textile    | NULL |
+----+-------+------+------------+------+

使用条件构建器构建查询

public List<Employee> getEmployees() {

    CriteriaBuilder cb = entityManager.getCriteriaBuilder();
    CriteriaQuery<Employee> q = cb.createQuery(Employee.class);
    Root<Employee> emp = q.from(Employee.class);
    Predicate year_like = cb.like(emp.<Integer>get("year").as(String.class), "%17%");
    CriteriaQuery<Employee> fq = q.where(year_like);

    List<Employee> resultList = (List<Employee>) entityManager.createQuery(fq).getResultList();
    return resultList;
}

生成查询(使用show_sql:true)

Hibernate: select employee0_.id as id1_0_, employee0_.first as first2_0_, employee0_.last as last3_0_, employee0_.occupation as occupati4_0_, employee0_.year as year5_0_ from Employee employee0_ where cast(employee0_.year as char) like ?

查询输出

// i have printed only id and year in the console
id, year
2, 1718
4, 1917

----------------------------------------------- -------------

替代方式
当使用JPA,hibernate,mysql进行测试时, LIKE 在JPA中用于数字字段。
注意: - 可能无法与其他jpa提供商一起使用

Query r = entityManager.createQuery("select c from Employee c where c.year like '%17%'");

查询已解雇(使用show_sql = true)

Hibernate: select employee0_.id as id1_0_, employee0_.first as first2_0_, employee0_.last as last3_0_, employee0_.occupation as occupati4_0_, employee0_.year as year5_0_ from Employee employee0_ where employee0_.year like '%17%'

查询结果

// i have printed only id and year in the console
id, year
2, 1718
4, 1917

答案 1 :(得分:0)

您可以声明自己的Criterion类型

public class CrazyLike implements Criterion {

    private final String propertyName;
    private final int intValue;

    public CrazyLike(String propertyName, int intValue) {
        this.propertyName = propertyName;
        this.intValue = intValue;
    }

    @Override
    public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
            throws HibernateException {
        final String[] columns = criteriaQuery.findColumns( propertyName, criteria );
        if ( columns.length != 1 ) {
            throw new HibernateException( "Crazy Like may only be used with single-column properties" );
        }

        final String column = columns[0];
        return "cast(" + column + " as text) like  '%" + intValue + "%'";
    }

    @Override
    public TypedValue[] getTypedValues(Criteria criteria,
            CriteriaQuery criteriaQuery) throws HibernateException {
        return new TypedValue[] { };    
    }

}

然后像这样使用它:

Criteria criteria = session.createCriteria(Person.class);
List<Person> persons = criteria.add(new CrazyLike("year", 17)).list();

假设Person有一个名为 year 的int属性。这应该产生这样的SQL:

select
    this_.id as id1_2_0_,
    this_.birthdate as birthdat2_2_0_,
    this_.firstname as firstnam3_2_0_,
    this_.lastname as lastname4_2_0_,
    this_.ssn as ssn5_2_0_,
    this_.version as version6_2_0_,
    this_.year as year7_2_0_ 
from
    Person this_ 
where
    cast(this_.year as text) like  '%17%'

这是用Postgres测试的。 cast()语法可能因数据库引擎而异。如果是,只需在您实现的Criterion类中使用该语法。