我在弄清楚如何使用play-slick更新带有类型枚举的列时遇到了麻烦。
这是我的枚举和案例类:
object TestStatus extends Enumeration {
type TestStatus = Value
val Status1 = Value("Status1")
}
case class Test (
id: String,
status: TestStatus
)
和表映射:
class Tests(tag: Tag) extends Table[Test](tag, "tests") {
implicit val statusColumn = MappedColumnType.base[TestStatus, String](_.toString, TestStatus.withName)
override def * = (id, status) <> ((Test.apply _).tupled, Test.unapply)
val id = column[String]("id", 0.PrimaryKey)
val status = column[TestStatus]("status")
}
当我尝试更新"测试"行时,出现错误:
object TestQueries extends TableQuery[Tests](new Tests(_)) {
def updateStatus(id: String, newStatus: TestStatus) = {
TestQueries.filter(_.id === id).map(_.status).update(newStatus)
}
}
[error] Slick does not know how to map the given types.
[error] Possible causes: T in Table[T] does not match your * projection,
[error] you use an unsupported type in a Query (e.g. scala List),
[error] or you forgot to import a driver api into scope.
[error] Required level: slick.lifted.FlatShapeLevel
[error] Source type: slick.lifted.Rep[models.TestStatus.Value]
[error] Unpacked type: T
[error] Packed type: G
[error] TestQueries.filter(_.id === id).map(_.status).update(newStatus)
[error] ^
IntelliJ 显示TestQueries.filter(_.id === id).map(_.status)
具有类型Query[Nothing, Nothing, Seq]
,这让我认为问题出在特定的列而不是更新功能上。
使用相同的结构更新 id 可以正常工作。
您需要定义TestStatus.Value
的自定义列类型。这就是 slick 允许您通过将自定义列类型映射到已支持的类型来构建自定义列类型的方式:
implicit def testStatCT: BaseTypedType[TestStatus.Value] =
MappedColumnType.base[TestStatus.Value, String](
enum => enum.toString, str => TestStatus.withName(str)
)
只要隐式解决方案(例如示例中的隐式解决方案)失败(或者在TestStatus
对象中定义得更好,以便它始终可用),就需要导入此隐式解决方案,这样 Slick 就可以证明TestStatus.Value
是一个BaseTypedType
,这基本上只是意味着某些东西是受支持的列类型。
有关列映射的进一步阅读,您可以查看光滑文档