2012-11-01 145 views
2

我通过JPA使用Hibernate,并且需要按照其Date属性的时间部分筛选记录。JPA和Hibernate:仅比较时间戳的部分时间

public class Foo { 
    Date getDateTime() { 
     // Returns a date and time value. 
    } 
} 

Time startTime = ...; 
Time endTime = ...; 

TypedQuery<Foo> query = entityManager.createQuery("SELECT foo FROM Foo foo where :startTime <= foo.dateTime AND foo.dateTime <= :endTime", Foo.class); 
query.setParameter("startTime", startTime); 
query.setParameter("endTime ", endTime); 

当然,这是行不通的,因为你不能直接比较一个DateTime。如果这是一个SQL查询,那么我会使用几个DBMS特定的日期函数来比较它们,但是如何比较JPA中的日期和时间?

+0

您使用java.sql.Time吗? –

+0

这是正确的。 –

+0

只是为了澄清...您想要查询具有日期时间列的记录,但只能与该列的hh:mm:ss.SSS组件进行比较。或者换句话说,“给我一天中发生的所有记录”。正确? – kaliatech

回答

2

为什么不使用本机查询,然后利用您熟悉的数据库特定功能。一旦你有本地查询,你可以将java.sql.Time对象转换成长整型并执行它。

EntityManager API Documentation

例如,如果你使用的是Oracle。

  long MILLIS_PER_DAY = 24 * 60 * 60 * 1000; 
    long startTimeMillis = (startTime.getTime() % MILLIS_PER_DAY)/1000; 
    long stopTimeMillis = (endTime.getTime() % MILLIS_PER_DAY)/1000; 
    entityManager 
      .createNativeQuery(
        "select * from foo where to_number(to_char(date_time, 'sssss')) between ?1 and ?2", Foo.class) 
      .setParameter(1, startTimeMillis) 
      .setParameter(2, stopTimeMillis).getResultList(); 

的实际查询将根据你的数据库的味道有所不同,但是创造了NativeQuery应该允许您利用特定于数据库的底层供应商的职能。

解决这一难题的另一种方法是创建一个视图,其中包含一个列,该列包含具有日期数据类型的列的时间部分。这将允许您以代码中透明的方式利用底层数据库技术。一旦设置了此列,您就可以在查询中建立适当的where子句。

+0

如果'sssss'从午夜(而不是毫秒)返回秒数,那么我认为在将它们作为查询的参数插入之前,需要将startTimeMillis和stopTimeMillis除以1000。 – kaliatech

+0

@kaliatech这是一个好点,我当然错过了。有没有办法告诉Oracle从午夜返回毫秒? –

+0

我不知道使用to_char的任何简单方法。这是[一种可能的解决方案](http://www.dba-oracle。com/t_date_format_hundredths_second.htm)。 – kaliatech

3

如果您使用的是JPA,您可以使用 @Temporal(TemporalType.TIME) 它将只返回TIMESTAMP的Time部分。 像: @Temporal(TemporalType.TIME) 日期getDateTime()

1

没有任何一个简单的或标准化的方法来比较反对使用JPA2现有的datetime /时间戳列只是时间(或日期)组成。选项:

  1. 使用本机查询kmb385's answer如果您需要秒精度(不是毫秒),则可以使用。我认为更常见的本机SQL方法是使用CAST或EXTRACT来仅与时间组件进行比较。

  2. 将另一列添加到表格/视图中,该列仅包含日期时间的时间组件,并使用该列进行比较。您可能还会使用@Temporal(TemporalType.TIME)注释向Foo添加另一个字段。

+0

只是好奇为什么我的方法不能仅仅匹配时间部分? –

+0

我最初误解了'sssss'格式在Oracle中的作用。我刚才查了一下,并同意,你的答案会按预期工作(我会在评论中注意到一个小小的改正)。我现在编辑我的答案以避免混淆。 – kaliatech