我有一个具有数字字段的JPA实体。类似的东西:
@Basic(optional = false)
@Column(name = "FISCAL_YEAR", nullable = false)
private int fiscalYear;
我要求子字符串搜索此字段。例如,我想要搜索17
,以便为我2017
和1917
以及1789
。暂时忘记这是一个疯狂的请求,并假设我有一个真正有用的用例。无法选择将列更改为数据库中的varchar。
在PL / SQL中,我将字段转换为varchar并执行like '%17%'
。如何在不使用本机查询的情况下使用Hibernate / JPA实现此目的?我需要能够使用HQL或Criteria来做同样的事情。
答案 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
类中使用该语法。