Java 如何使用JPA标准API搜索字符串的日期字段

Java 如何使用JPA标准API搜索字符串的日期字段,java,mysql,jpa,Java,Mysql,Jpa,这是我另一个问题的衍生问题。我想最好在有人给我指了指后,把它作为一个不同的问题提出来 如何使用JPA Criteria API在数据库日期列(在我的例子中是MySQL DATETIME)中搜索字符串,这让我感到困惑。 以下是我所做的 CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<Client> cq = cb.createQuery(Client.class); Root<Client> entit

这是我另一个问题的衍生问题。我想最好在有人给我指了指后,把它作为一个不同的问题提出来

如何使用JPA Criteria API在数据库日期列(在我的例子中是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();
其中
10-2015
是正在搜索的字符串


我被困在如何实现这一目标上。我需要一些帮助。

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

SimpleDateFormat dateFormat = new SimpleDateFormat(...desired date format here...);
Date dateSearchParam = dateFormat.format(search);
predicates.add(cb.eq(entity.get("dateJoined"), dateSearchParam);
或者,如果需要,可以将实体中的datejoin属性的类型更改为String,而MySQL DB类型保持为DATETIME。当从DB中检索实体时,可以利用JPA@Convert将DATETIME转换为java.lang.String(当实体被持久化到DB时,反之亦然)

看一个例子


属性转换器仅在JPA2.1版本中可用。

好的,在对各种策略进行了大量试验之后,下面是我最终成功的做法

我看到这篇文章,突然想起了JPA接口,它是一个可以返回多个结果类型的对象。因此,要执行类似于比较的
,并且由于日期不能简单地转换为字符串,以下是步骤

  • 我将列作为
    元组
  • 对Tuple对象进行检查,查看它是否可以从Date赋值
  • 如果是,则获取日期格式表达式并将其传递给
    like
    表达式
  • 所以本质上,这就是我最初拥有的,显然是失败的

    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()+"%"));
    }
    
    Path tuple=entity.get(“dateJoined”);
    if(tuple.getJavaType().isAssignableFrom(Date.class)){
    表达式dateStringExpr=cb.function(“DATE_格式”,String.class,entity.get(“dateJoined”),cb.literal(“%d/%m/%Y%r”);
    add(cb.like(cb.lower(dateStringExpr),“%”加上search.toLowerCase()+“%”);
    }
    
    值得注意的注意事项-

  • 我知道,无论搜索从何处开始,我的所有日期都以这种形式显示
    07/10/2015 10:25:09 PM
    ,因此我能够知道如何将我的
    类似的
    表达式中的比较日期格式化为
    “'%d/%m/%Y%r'
  • 这只是对日期有效的一个步骤。大多数其他类型,例如int、long、char…等。。。可以直接转换为字符串,当我探索更多类型的数据时,我肯定会对任何其他不能直接转换为字符串的类型执行相同的操作
  • 虽然这对我来说非常有效,但在我将其标记为正确答案之前,我将对其进行更广泛的测试,并在测试过程中对任何对我的策略有任何保留意见的人都可以对其进行评论

    最后,对于这个在任何方面都有所帮助的人。。。干杯

    这在我的案例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 + "%"));
    
    Path-Path=ua.get(MyEntity\uuuu.timestamp);
    表达式dateStringExpr=cb.function(“TO_CHAR”,String.class,path,cb.literal(“DD.MM.YYYY HH24:MI:SS”);
    add(cb.like(dateStringExpr,“%”+value+“%”);
    

    PS.
    MyEntity
    代表为real
    MyEntity
    生成的元模型。您可以在Oracle DocuemStation for中阅读有关元模型的内容。

    日期字段不是文本!数据库为您提供了搜索日期范围的方法。如果您希望从2015年10月开始搜索所有内容,则需要搜索从10月1日到10月31日的日期范围。像“%10-2015”这样的文本搜索是不可能的。实际上,不是我。是@Franck提出的建议:在DB端使用SQL函数来_CHAR@Ish... 哦,糟糕!参考资料现已更正。谢谢这里的问题是搜索字符串不一定是日期字符串,也可能无法格式化为日期对象。。。。例如:如果有一个html表格,其中一列中显示了日期,用户可能会决定只键入部分日期的搜索文本字段,例如“10-2015”,并希望获得所有包含该文本的行。我希望您现在就明白了。然后,当您已经将搜索字符串与dateJoined列进行比较时,进行条件检查,然后应用我给出的代码。否则,对于其他列,在Criteria.Getting error“Internal Exception:org.postgresql.util.psqleException:function date_format(不带时区的时间,字符变化)中执行普通字符串到字符串的比较不存在提示:没有函数与给定的名称和参数类型匹配。您可能需要添加显式类型转换。位置:82错误代码:0调用:从icom_leader.t_run t0、icom_leader.t_tripfile t1中选择计数(t0.ID),其中((DATE_FORMAT(t1.BEGINTIME,)=?)和(t1.ID=t0.fk_tripfile_ID))bind=>['HH24:MI',11:18]”显然,您正在使用postgres数据库。因此,您需要在postgres中找到与MySQL的
    DATE\u格式
    函数等效的函数名。不幸的是,这是编写这些类型表达式的背景之一,因为它使您失去了JPA Criteria查询的数据库不可知优势。你说得对,Postgresql现在支持“to_char”函数。我曾经使用过to_char函数,在控制台中执行查询时效果很好,但“通过CriteriaBuilder使用时查询不返回任何结果”。知道是什么阻止了它吗?对于引用,表达式是*cb.function(“to_uchar”、String.class、entity.get(propertyName)、cb.literal('HH24:MI')*
    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 + "%"));