scala 有条件地将可为空的字段Map到slick中的None值

t9eec4r0  于 2022-11-09  发布在  Scala
关注(0)|答案(2)|浏览(134)

在slick 2.1中,我需要执行查询/map操作,在该操作中,如果可空字段包含某个非空值,则将其转换为None。我不确定这是否重要,但在我的例子中,有问题的列类型是Map列类型。下面是一段代码片段,它试图说明我想要做的事情。它不会编译,因为编译器不喜欢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?不是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
    }
  }

}
qyswt5oh

qyswt5oh1#

我需要执行查询/Map操作,在该操作中,如果可空字段包含某个非空值,则将其转换为None
给出您在更新中拥有的示例数据,并假装1是您所关心的“特定”值,我相信这就是您预期的输出:

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"
ruarlubt

ruarlubt2#

您需要将MyValue Package 在一个选项中,以便条件的两个结果都是选项。在Slick 2.1中,您使用.?接线员。在SLICK 3.0中,它很可能是代表。
尝试

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

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

相关问题