如何在Slick 3.1中编译参数化更新?

Sar*_*h G 5 scala slick-3.0

尽管文档说您可以编译更新,但是我无法让Slick 3.1编译更新,而将要更新的值传递到已编译的块中。

对于我的用例,我想找到一个具有给定键的行,其中停用为空,并将停用时间设置为新的时间戳。

我想做的显而易见的事情是:

  private[this] lazy val updateDeactiveTime = Compiled { (settingName: Rep[String], time: Rep[Instant]) =>
    settings
      .filter { row => row.name === settingName && row.deactivatedAt.isEmpty }
      .map { _.deactivatedAt }
      .update(Some(time))
  }
Run Code Online (Sandbox Code Playgroud)

不幸的是,这给了我一个update不能接受的投诉Rep[Option[Instant]]:它想要一个Option[Instant]

我了解Slick(不幸的是)不允许您在更新中使用动态计算的值。根据文档,限制操作之类的解决方法是使用ConstColumn[…]。尽职尽责,我尝试传递a ConstColumn[Option[Instant]],希望会有一些隐式转换或扩展,但是我仍然抱怨它必须是文字Option[Instant]

当然,我有立即数,但是如果每次目标值更改时都必须重新编译更新,那么编译更新没有多大意义。

如果我使用a LiteralColumn[…],我可以打电话_.value,但是Compiled不会让我要求a LiteralColumnCompiled也不允许我将参数设为time: Instant

Sar*_*h G 6

您在编译的部分之外执行update操作。这仍然提供了编译的好处。

  private[this] lazy val deactiveTime = Compiled { (settingName: Rep[String]) =>
    settings
      .filter { row => row.name === settingName && row.deactivatedAt.isEmpty }
      .map { _.deactivatedAt }
  }
  def updateDeactiveTime(settingName: String, time: Instant) = {
    deactiveTime(settingName).update(Some(time))
  }
Run Code Online (Sandbox Code Playgroud)

事实证明,当您这样做时Compiled,Slick 实际上会创建四个不同的编译目标,用于插入、更新、删除和选择。每个特定的表格在第一次使用时都被完全编译。您可以在CompiledFunctionAPI 中明确看到这一点。