如何使用JPA Criteria API

时间:2015-10-15 15:54:38

标签: java mysql jpa

这是一个转移我的另一个问题here的问题。在某人(@Franck)将我指向this linkthis one too后,我认为最好将其作为一个不同的问题。

我对如何使用JPA Criteria API在数据库Date列(在我的案例中是MySQL DATETIME)中搜索字符串感到困惑。

这就是我所做的;

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Client> cq = cb.createQuery(Client.class);
Root<Client> entity = cq.from(Client.class);
cq.select(entity);

List<Predicate> predicates = new ArrayList<Predicate>();
predicates.add(cb.like(cb.lower(entity.get("dateJoined").as(String.class)), "%"+search.toLowerCase()+"%")); 

cq.where(predicates.toArray(new Predicate[]{}));
TypedQuery<Client> query = em.createQuery(cq); //<--- Error gets thrown here
return query.getResultList();

但它失败并出现以下异常;

java.lang.IllegalArgumentException: Parameter value [%10-2015%] did not
match expected type [java.lang.Character]
     

其中10-2015是要搜索的字符串;

我坚持如何实现这一目标。我需要一些帮助。

3 个答案:

答案 0 :(得分:4)

好的,经过大量的各种策略试验,这就是我最终的工作。

我看到了这篇文章here,突然想起了JPA Tuple接口,它是一个可以返回多个结果类型的对象。所以要执行我的like比较,并且因为Date不能简单地转换为字符串,这里是步骤;

  1. 我将列作为Tuple
  2. 检查The Tuple Object以查看它是否可以从Date
  3. 分配
  4. 如果是,则获取Date-Format表达式并将其传递给like表达式。
  5. 从本质上讲,这是我最初所拥有的显然失败的原因;

    predicates.add(cb.like(cb.lower(entity.get("dateJoined").as(String.class)), "%"+search.toLowerCase()+"%")); 
    

    现在,这就是我的作品,它的作品非常漂亮;

    Path<Tuple> tuple = entity.<Tuple>get("dateJoined");
    if(tuple.getJavaType().isAssignableFrom(Date.class)){
        Expression<String> dateStringExpr = cb.function("DATE_FORMAT", String.class, entity.get("dateJoined"), cb.literal("'%d/%m/%Y %r'"));
        predicates.add(cb.like(cb.lower(dateStringExpr), "%"+search.toLowerCase()+"%"));
    }
    

    注意 - 值得考虑的事项 -

    1. 我知道,从搜索开始的任何地方开始,我的所有日​​期都会以07/10/2015 10:25:09 PM格式显示,因此我能够知道如何格式化我的like表达式中的比较日期"'%d/%m/%Y %r'"
    2. 这只是日期的一个步骤。大多数其他类型,例如int,long,char ......等......都可以直接转换为String,当我探索更多类型的数据时,对于任何其他无法直接转换的类型,我都会做同样的事情。字符串。
    3. 虽然这对我来说非常合适,但在我将其标记为正确答案之前,我会对其进行更广泛的测试,并在此过程中保持开放以供任何有任何保留意见的人发表评论。我的策略。

      最后,对于那个以任何方式帮助过的人......干杯!

答案 1 :(得分:1)

这适用于我的情况H2(我用它进行单元测试),我希望在Postgresql和Oracle中也能正常工作,因为TO_CHAR函数似乎支持跨数据库。

Path<Date> path = ua.get(MyEntity_.timestamp);
Expression<String> dateStringExpr = cb.function("TO_CHAR", String.class, path, cb.literal("DD.MM.YYYY HH24:MI:SS"));
predicates.add(cb.like(dateStringExpr, "%" + value + "%"));

PS。 MyEntity_代表为真实MyEntity生成的元模型。您可以在Oracle docuemntation中阅读有关Criteria API的元模型。

答案 2 :(得分:0)

我建议你将搜索字符串转换为Date对象,并进行比较

SimpleDateFormat dateFormat = new SimpleDateFormat(...desired date format here...);
Date dateSearchParam = dateFormat.format(search);
predicates.add(cb.eq(entity.get("dateJoined"), dateSearchParam);

或者,如果需要,可以将Entity中dateJoined属性的类型更改为String,而MySQL DB类型仍为DATETIME。当从DB中检索实体时,您可以利用JPA @Convert将DATETIME转换为java.lang.String(反之亦然,当实体被持久化到DB时)。

查看示例here

属性转换器仅适用于JPA 2.1版本。