【问题标题】:Slick: Filtering all records which have a joda DateTime date equal to todaySlick:过滤所有 joda DateTime 日期等于今天的记录
【发布时间】:2014-01-27 01:51:28
【问题描述】:

实现它的一种方法是这样的:

val now = DateTime.now

val today = now.toLocalDate
val tomorrow = today.plusDays(1)

val startOfToday = today.toDateTimeAtStartOfDay(now.getZone)
val startOfTomorrow = tomorrow.toDateTimeAtStartOfDay(now.getZone)

val todayLogItems = logItems.filter(logItem =>
  logItem.MyDateTime >= startOfToday && logItem.MyDateTime < startOfTomorrow
).list

有什么方法可以更简洁地编写查询吗?大致如下:

logItems.filter(_.MyDateTime.toDate == DateTime.now.toDate).list

我问这个是因为在 LINQ to NHibernate 中这是可以实现的 (Fetching records by date with only day part comparison using nhibernate)。

【问题讨论】:

  • 别忘了使用 === 而不是 ==

标签: scala jodatime slick


【解决方案1】:

除非 Slick joda 映射器添加了对比较的支持,否则除非您自己添加,否则您将不走运。为了试一试,这些可能是有用的指示: * http://slick.typesafe.com/doc/2.0.0/userdefined.html * http://slick.typesafe.com/doc/2.0.0/api/#scala.slick.lifted.ExtensionMethods * https://github.com/slick/slick/blob/2.0.0/src/main/scala/scala/slick/lifted/ExtensionMethods.scala

我创建了一张票在 Slick 中查看它:https://github.com/slick/slick/issues/627

【讨论】:

    【解决方案2】:

    使用 LocalDateTimes 而不是直接使用 LocalDates 会造成混淆:

    val today = LocalDate.now
    val todayLogItems = logItems.filter(_.MyDateTime.toLocalDate isEqual today)
    

    更新

    这里的问题需要主要澄清一下,Slick 只是顺便提及,通过标签。

    但是... Slick 是这个问题的核心,这取决于 filter 操作实际上是通过 PlainColumnExtensionMethods 进入 SQL 查询的事实

    我对这个库并不太熟悉,但这肯定意味着您仅限于可以在 SQL 中执行的操作。由于这是一个 Column[DateTime],因此您必须将其与另一个 DateTime 进行比较。

    对于 LINQ 示例,似乎建议首先获取所有内容,然后按照我上面的示例继续(在 Scala 中而不是在 SQL 中执行比较)。这是一个选项,但我怀疑您不会想要它所带来的性能成本。

    更新 2(只是为了澄清)

    没有答案。

    无法保证您的底层数据库能够在日期和时间戳之间进行相等性检查,因此 slick 不能依赖现有的这种能力。

    你被困在一块石头和一个坚硬的地方之间。要么像你一样在时间戳之间进行范围检查,要么从查询中提取所有内容并在 Scala 中对其进行过滤——这可能会带来沉重的性能成本。

    最终更新

    要参考您引用的 Linq/NHibernate 问题,这里有几个引号:

    • 您还可以通过 SqlFunction 使用 Criteria 中的日期函数
    • 这取决于 LINQ 提供程序
    • 我不确定 NHibernate LINQ 提供程序是否支持...

    所以答案似乎是:

    • 依靠 NHibernate 将日期强制逻辑推送到数据库中,如果这是不可能的,可能会默默地削弱性能(通过获取所有记录并在本地过滤)
    • 靠你写自定义SQL逻辑

    最好的情况是 NHibernate 可以将日期/时间戳比较转换为时间戳范围检查。做这样的事情是一个关于 Slick(和 slick-joda-mapper)如何处理比较的非常深刻的问题,您在过滤器中使用它的事实是偶然的。

    考虑到创建复杂错误的风险,您需要非常引人注目的用例来自己编写这样的功能。你会过得更好:

    • 将列拆分为单独的日期/时间列
    • 将日期添加为计算列(可能在视图中)
    • 使用自定义 SQL(或存储过程)进行查询
    • 坚持范围检查
    • 使用辅助函数

    在助手的情况下:

    def equalsDate(dt: LocalDate) = {
      val start = dt.toDateTimeAtStartOfDay()
      val end = dt.plusDays(1).toDateTimeAtStartOfDay()
      (col: Column[DateTime]) => {
        col >= start && col < end
      }
    }
    
    val isToday = equalsDate(LocalDate.now)
    val todayLogItems = logItems.filter(x => isToday(x.MyDateTime))
    

    【讨论】:

    • 这不起作用,因为_.MyDateTime 没有toLocalDate 方法,因为它是Column[Imports.DateTime] 类型。
    • 我正在从https://github.com/tototoshi/slick-joda-mapper 导入import com.github.tototoshi.slick.H2JodaSupport._,这使它能够按照我的示例中使用的方式工作。但是访问 MyDateTime 的成员不起作用。
    • slick 作为标签和问题中的第二个示例(它不起作用,但如果它仅在内存中运行则可以)足以清楚地说明问题上下文是什么。抱歉,我无法投票或接受您的 answer,因为它没有回答问题。
    • 如果没有答案就没有问题。从数据库中检索所有数据只是为了在内存中查询它不是一个解决方案,因为这已经可以使用问题中提到的方法在数据库中完成,而不会受到任何惩罚。数据库不需要支持时间戳比较以外的任何东西,LINQ 可以在不考虑数据库的情况下执行该查询,这证明 Slick 也可以做到。无论如何,为你的努力 +1。
    猜你喜欢
    • 2021-08-09
    • 2012-08-10
    • 2021-12-01
    • 1970-01-01
    • 2014-08-12
    • 1970-01-01
    • 1970-01-01
    • 2022-08-20
    • 1970-01-01
    相关资源
    最近更新 更多