【问题标题】:Slick - implicit conversion of Long to java.sql.TimestampSlick - Long 到 java.sql.Timestamp 的隐式转换
【发布时间】:2015-11-13 22:22:25
【问题描述】:

光滑 2.1 斯卡拉 2.11.7

无法获得 Long java.sql.Timestamp 或 java.sql.Date 工作的隐式转换。我让他们为其他转换工作,例如 JodaTime.DateTime java.sql.Timestamp...

例如查询返回错误:

org.postgresql.util.PSQLException: ERROR: operator does not exist: 
timestamp with time zone >= bigint Hint: No operator matches 
the given name and argument type(s). You might need to add explicit type casts. 
Position: 325

这些是隐含的,它们肯定被正确导入以在范围内:

implicit val LongToTimestamp = MappedColumnType.base[Long, Timestamp](
longTS => new Timestamp(longTS),
sqlTS => sqlTS.getTime
)

implicit val LongToDate = MappedColumnType.base[Long, java.sql.Date](
longTS => new java.sql.Date(longTS),
sqlDate => sqlDate.getTime
)

我也尝试过使用 java.lang.Long 代替:

implicit val LongToTimestamp = MappedColumnType.base[java.lang.Long, Timestamp](
longTS => new Timestamp(longTS),
sqlTS => sqlTS.getTime
)

implicit val LongToDate = MappedColumnType.base[java.lang.Long, java.sql.Date](
longTS => new java.sql.Date(longTS),
sqlDate => sqlDate.getTime
)

我在这里缺少什么?谢谢!

--

附加信息:

查询方法定义为(queued is a java.sql.Timestamp):

def getJobs(jobTypeId: Short, onOrAfter: DateTime): Seq[JobRow] = {
 val q1 = for{j <- Jobs if j.jobTypeId === jobTypeId && j.queued >= onOrAfter.getMillis} yield j
 db.withSession{ implicit s =>
   q1.buildColl[Seq]
 }
}

表定义:

class Jobs(tag: Tag) extends Table[JobRow](tag, "job") {

def jobId = column[Long]("job_id", O.PrimaryKey, O.NotNull)

def jobTypeId = column[Short]("job_type_id", O.NotNull)

def queued = column[Long]("queued", O.NotNull)

def * = (jobId, jobTypeId, queued) <>((JobRow.apply _).tupled, JobRow.unapply_ )

def pk = primaryKey("job_pk", jobId)
}

【问题讨论】:

  • 问题不在于您的映射,而在于您的查询 - 您能告诉我们您是如何生成查询的吗? ( Long 按原样绑定,未转换为时间戳,导致错误)。或者,您的隐含可能会被 Slick 的默认隐含所掩盖。
  • 感谢您的浏览。我添加了表定义和查询示例。感觉就像你的第二个想法,Slick 的默认隐式正在占据主导地位,而我的被忽略了。不知道怎么解决。

标签: postgresql scala slick


【解决方案1】:

您的问题是 Postgres 中的基础 queued 列不是 bigint 而是 timestamp with time zone。但是,在 Slick 的 Jobs 表定义中,您说该列是 Long。 Slick 已经知道如何将 Long 绑定到查询,因此它永远不会尝试使用您的隐式将 Long 转换为它确实知道如何绑定的另一种类型。

理想情况下,您只需使用 sql.Timestamp 作为您的 Jobs.queued 列类型(这就是您对查询 sn-p 的评论似乎表明您 认为它是):

def queued = column[Timestamp]("queued", O.NotNull)
// As opposed to your example where this is
// def queued = column[Long]("queued", O.NotNull)

或者,您可以为 to_timestamp(double) 创建一个 Slick 包装器:

val toTimestamp = SimpleFunction.unary[Double, Timestamp]("to_timestamp")
val q1 = for {
  j <- Jobs
  if j.jobTypeId === jobTypeId && j.queued >= toTimestamp(onOrAfter.getMillis)
} yield j

最后,您可以将自动转换添加到 Postgres DB 以进行转换。

【讨论】:

  • 谢谢肖恩。我天真地认为我的隐式会被使用,因为 Slick 没有 Long Timestamp 绑定。是否有解决方案可以在 Slick 端完成 Long Timestamp 转换而不涉及 DB 函数或特性?从那以后,我继续在我的模型中使用 ZonedDateTime,隐含的,但这仍然困扰着我。
  • 问题是您告诉 Slick 该列是 Long - Slick 不会根据实际表的架构仔细检查您的架构,因此它很乐意从 @987654333 绑定 Long @ 查询,导致 Postgres 抛出错误。如果您从 def queued = column[Long] 更改为 def queued = column[Timestamp] 您会在您的 getJobs 方法中在编译时得到不同的错误,然后您可以解决这些错误。
  • 如果使用 column[Timestamp],但 Long 维护 JobRow 类,是否会通过 Long Timestamp 之间的隐式转换工作?还是我需要在 def * = ... 行中定义自定义转换?
  • 您需要在映射* 方法中进行自定义转换。
猜你喜欢
  • 1970-01-01
  • 2020-06-02
  • 1970-01-01
  • 2018-12-01
  • 1970-01-01
  • 2013-03-23
  • 1970-01-01
  • 2012-05-23
  • 1970-01-01
相关资源
最近更新 更多