有条件地将可空字段映射到 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"
在 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"