映射列类型 Slick 3.1.1

Posted

技术标签:

【中文标题】映射列类型 Slick 3.1.1【英文标题】:Mapping column types Slick 3.1.1 【发布时间】:2016-02-17 08:34:07 【问题描述】:

我是 Slick 的新手,很难将 java.sql.date/time/timestamp 映射到 jodatime。

trait ColumnTypeMappings 

  val profile: JdbcProfile
  import profile.api._

  val localTimeFormatter = DateTimeFormat.forPattern("HH:mm:ss")
  val javaTimeFormatter = new SimpleDateFormat("HH:mm:ss")

  implicit val myDateColumnType = MappedColumnType.base[LocalDate, Date](
    ld => new        java.sql.Date(ld.toDateTimeAtStartOfDay(DateTimeZone.UTC).getMillis),
    d  => new LocalDateTime(d.getTime).toLocalDate
  )

  implicit val myTimeColumnType = MappedColumnType.base[LocalTime, Time](
    lt => new java.sql.Time(javaTimeFormatter.parse(lt.toString(localTimeFormatter)).getTime),
    t  => new LocalTime(t.getTime)
  )

  implicit val myTimestampColumnType = MappedColumnType.base[DateTime, Timestamp](
    dt => new java.sql.Timestamp(dt.getMillis),
    ts => new DateTime(ts.getTime, DateTimeZone.UTC)
  )


在自动生成的 Tables.scala 中,我包含如下映射:

trait Tables extends ColumnTypeMappings 
  val profile: slick.driver.JdbcDriver
  import profile.api._
  import scala.language.implicitConversions
  // + rest of the auto generated code by slick codegen

为了总结它,我这样使用:

object TestTables extends Tables 
  val profile = slick.driver.mysqlDriver


import Tables._
import profile.api._

val db = Database.forURL("url", "user", "password", driver = "com.mysql.jdbc.Driver")
val q = Company.filter(_.companyid === 1).map(._name)
val action = q.result
val future = db.run(action)
val result = Await.result(future, Duration.Inf)

运行此程序时,我得到一个 NullPointerException on:implicit val myDateColumnType....。如果我删除映射,我已经验证了最后一段代码是否有效。

【问题讨论】:

你好,我没有尝试你的代码,但是如果你有很多jodatime的用法,你可以试试slick-pg,github.com/tminglei/slick-pg。它提供了 jodatime 和其他流行的类型映射。 【参考方案1】:

尝试在MappedColumnTypes 的定义中将implicit val 更改为implicit def。原因与Maksym Chernenko给这个question的答案有关。通常,JdbcProfile 驱动程序(定义api.MappedColumnType)尚未注入,并且:

这会导致 NPE。你可以让你的“映射器”vallazy,或者改变它 从valdef(如下图)

implicit def myDateColumnType = MappedColumnType.base[LocalDate, Date](
  ld => new java.sql.Date(ld.toDateTimeAtStartOfDay(DateTimeZone.UTC).getMillis),
  d  => new LocalDateTime(d.getTime).toLocalDate
)

implicit def myTimeColumnType = MappedColumnType.base[LocalTime, Time](
  lt => new java.sql.Time(javaTimeFormatter.parse(lt.toString(localTimeFormatter)).getTime),
  t  => new LocalTime(t.getTime)
)

implicit def myTimestampColumnType = MappedColumnType.base[DateTime,  Timestamp](
  dt => new java.sql.Timestamp(dt.getMillis),
  ts => new DateTime(ts.getTime, DateTimeZone.UTC)
)

【讨论】:

【参考方案2】:

所以我认为问题可能是您在 Tables.scala 中扩展 ColumnTypeMappings。文档没有说清楚,但我认为不应该触及与数据库相关的自动生成代码,因为 slick 使用它来映射数据库中的行,然后通过 ColumnTypeMappings 扩展 TestTables 以执行隐式转换你从数据库中得到结果。

我还没有特别深入研究 slick 3.x,所以我可能错了,但我认为这是有道理的。

编辑:不,我错了:(。道歉

【讨论】:

你确定导入了 java.sql.Date 还是 LocalDateTime?这些将需要在隐式转换的范围内

以上是关于映射列类型 Slick 3.1.1的主要内容,如果未能解决你的问题,请参考以下文章

在 slick、scala 中处理 Postgres json 数据类型

slick对超过22个属性的表进行映射的两种办法

播放光滑的更新枚举列

使用 Slick 输入投影

映射数据流列模式类型 =='decimal' 不更改十进制列

休眠映射异常:无法确定列的类型