【发布时间】:2016-09-01 15:09:23
【问题描述】:
由于类型推断问题,我很难在我的案例类和数据库表之间获得自定义定义的映射。这是我得到的一个例子,它只是原始用例的一个非常精简的版本,但它应该足以说明问题:
case class Example(id: Int, aString: String, optional: Option[Int], extra: String)
class Examples(tag: Tag) extends Table[Example](tag, "EXAMPLE") {
def id = column[Int]("ID", O.AutoInc, O.PrimaryKey)
def aString = column[String]("A_STRING")
def optional = column[Option[Int]]("AN_OPTIONAL")
override def * = (id, aString, optional) <> (constructExample, extractExample)
private def constructExample(id: Int, aString: String, optional: Option[Int]): Example = {
Example(id, aString, optional, "MY EXTRA DATA")
}
private def extractExample(e: Example): Option[(Int, String, Option[Int])] = {
Some((e.id, e.aString, e.optional))
}
}
在这里,我定义了 2 个自定义函数来处理我的案例类和数据库行之间的转换。问题是<> 方法无法推断出要构造的元组类型,出现以下错误:
错误:(60, 50) 类型不匹配; 找到 : (Int, String, Option[Int]) => SlickExampleRepository.this.Example 必需的: ? => ? 覆盖 def * = (id, aString, optional) (constructExample, extractExample)
在Slick docs 中可以找到以下内容:
它也可以与任意映射函数一起使用。在这些情况下,在左侧的元组上调用 .shape 可能很有用,以便正确推断其类型。否则,您可能必须向映射函数添加完整的类型注释。
没有例子,但我继续尝试以下方法:
override def * = (id, aString, optional).shaped <> (constructExample, extractExample)
这似乎只能部分解决问题,出现以下错误:
错误:(60, 57) 类型不匹配; 找到 : (Int, String, Option[Int]) => SlickExampleRepository.this.Example 必需: ((Int, String, Option[Int])) => ? 覆盖 def * = (id, aString, optional).shape (constructExample, extractExample)
因此,我为此找到的最终解决方法是更改 constructExample 函数的签名以接收元组并返回示例对象,如下所示:
private def constructExample(tuple: (Int, String, Option[Int])): Example = {
Example(tuple._1, tuple._2, tuple._3, "MY EXTRA DATA")
}
但这非常可怕且容易出错,因为我们正在定义可能相当长的元组并使用._1 等访问它的元素。有关如何使其以nice 方式工作的任何提示?
非常感谢
【问题讨论】:
-
可以从其他参数中推断出“额外”字段吗?我的意思是你真的需要自定义映射吗?因为您可以简单地这样做:覆盖 def * = (id, aString, optional) (Example.tupled, Example.unapply)
-
感谢您阅读冗长的问题和您的建议。事实是,我添加该字段只是为了用一个简短的示例来说明问题,但真正的用例更多的是围绕多个非规范化的数据库字段构建构成主要案例类的内部对象。例如,生成一个时间段的两个日期。