使用Slick 3进行自定义表映射类型推断

时间:2016-09-01 15:09:23

标签: scala slick-3.0

由于类型推断问题,我很难在我的案例类和数据库表之间获得自定义映射。这是我得到的一个例子,它只是原始用例的一个极度精简的版本,但它应该足以说明问题:

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))
  }
}

这里我定义了两个自定义函数来处理我的case类和数据库行之间的转换。问题是<>方法无法推断构造的元组类型,给出以下错误:

  

错误:(60,50)类型不匹配;    found:(Int,String,Option [Int])=&gt; SlickExampleRepository.this.Example    要求:? =&GT; ?       覆盖def * =(id,aString,optional)&lt;&gt; (constructExample,extractExample)

Slick docs中可以找到以下内容:

  

它也可以与任意映射函数一起使用。在这些情况下,在左侧的元组上调用.shaped可能很有用,以便正确推断其类型。否则,您可能必须向映射函数添加完整类型注释。

没有它的例子,但我继续尝试以下方法:

override def * = (id, aString, optional).shaped <> (constructExample, extractExample)

这似乎只能部分解决问题,给出以下错误:

  

错误:(60,57)类型不匹配;    found:(Int,String,Option [Int])=&gt; SlickExampleRepository.this.Example    required:((Int,String,Option [Int]))=&gt; ?       覆盖def * =(id,aString,optional).shaped&lt;&gt; (constructExample,extractExample)

所以我发现最后的解决方法是更改​​constructExample函数的签名以接收元组并返回一个Example对象,如下所示:

private def constructExample(tuple: (Int, String, Option[Int])): Example = {
  Example(tuple._1, tuple._2, tuple._3, "MY EXTRA DATA")
}

但这是非常可怕和容易出错的,因为我们正在定义可能很长的元组并使用._1等来访问它的元素。有关如何以nice方式使其工作的任何提示?

非常感谢

1 个答案:

答案 0 :(得分:0)

您应该使用以下方式定义*投影:

override def * = (id, aString, optional) <> ((constructExample _).tupled, extractExample)

constructExample _会将您的私有方法转换为函数,.tupled会将带有3个参数的函数转换为带有Tuple3个参数的函数。