有条件地将可空字段映射到 Slick 中的 None 值

Conditionally map a nullable field to None value in Slick

在 Slick 2.1 中,我需要执行查询/map 操作,如果它包含特定的非空值,我将可空字段转换为 None。不确定它是否重要,但在我的例子中,有问题的列类型是映射的列类型。这是一个代码片段,它试图说明我正在尝试做什么。它不会编译,因为编译器不喜欢 None.

case class Record(field1: Int, field2: Int, field3: MyEnum)

sealed trait MyEnum
val MyValue: MyEnum = new MyEnum { }

// table is a TableQuery[Record]
table.map { r => (
  r.field1,
  r.field2,
  Case If (r.field3 === MyValue) Then MyValue Else None // compile error on 'None'
  )
}

错误是这样的:

type mismatch; found : None.type required: scala.slick.lifted.Column[MyEnum]

实际上,我想这样做的原因是我想执行一个 groupBy,在其中计算 field3 包含给定值的记录数。我无法让更复杂的 groupBy 表达式工作,所以我退回到这个我仍然无法工作的更简单的例子。如果有更直接的方式向我展示 groupBy 表达式,那也很好。谢谢!

更新

我尝试了@cvogt 建议的代码,但这会产生编译错误。这是一个 SSCCE 以防有人发现我在这里做错了什么。编译失败 "value ? is not a member of Int":

import scala.slick.jdbc.JdbcBackend.Database
import scala.slick.driver.H2Driver

object ExpMain extends App {

  val dbName = "mydb"
  val db = Database.forURL(s"jdbc:h2:mem:${dbName};DB_CLOSE_DELAY=-1", driver = "org.h2.Driver")
  val driver = H2Driver

  import driver.simple._

  class Exp(tag: Tag) extends Table[(Int, Option[Int])](tag, "EXP") {
    def id = column[Int]("ID", O.PrimaryKey)
    def value = column[Option[Int]]("VALUE")
    def * = (id, value)
  }
  val exp = TableQuery[Exp]

  db withSession { implicit session =>
    exp.ddl.create

    exp += (1, (Some(1)))
    exp += (2, None)
    exp += (3, (Some(4)))

    exp.map { record =>
      Case If (record.value === 1) Then 1.? Else None  // this will NOT compile
      //Case If (record.value === 1) Then Some(1) Else None  // this will NOT compile
      //Case If (record.value === 1) Then 1 Else 0  // this will compile
    }.foreach {
      println
    }
  }

}

您需要将 MyValue 包装在一个 Option 中,以便条件的两个结果都是选项。在 Slick 2.1 中你使用 .?运营商。在 Slick 3.0 中,它可能是 Rep.Some(...).

尝试

Case If (r.field3 === MyValue) Then MyValue.? Else None

Case If (r.field3 === MyValue) Then MyValue.? Else (None: Option[MyEnum])

I need to perform a query/map operation where I convert a nullable field to None if it contains a certain non-null value

根据更新中的示例数据,假设 1 是您关心的 "certain" 值,我相信这就是您期望的输出:

None, None, Some(4)

(对于 ID 为 1、2 和 3 的行)

如果我理解正确的话,这是你需要的吗...?

val q: Query[Column[Option[Int]], Option[Int], Seq] = exp.map { record => 
  Case If (record.value === 1) Then (None: Option[Int]) Else (record.value)
}

...等同于:

select (case when ("VALUE" = 1) then null else "VALUE" end) from "EXP"