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

Posted

技术标签:

【中文标题】使用 Slick 3 进行自定义表映射类型推断【英文标题】:Custom table mapping type inference with Slick 3 【发布时间】: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 个自定义函数来处理我的案例类和数据库行之间的转换。问题是&lt;&gt; 方法无法推断出要构造的元组类型,出现以下错误:

错误:(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) 感谢您阅读冗长的问题和您的建议。事实是,我添加该字段只是为了用一个简短的示例来说明问题,但真正的用例更多的是围绕多个非规范化的数据库字段构建构成主要案例类的内部对象。例如,生成一个时间段的两个日期。 【参考方案1】:

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

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

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

【讨论】:

以上是关于使用 Slick 3 进行自定义表映射类型推断的主要内容,如果未能解决你的问题,请参考以下文章

映射列类型 Slick 3.1.1

从字符串 => 类型的映射推断反应道具类型时修复打字稿警告

resultMap自定义映射(多对一)

resultMap自定义映射(多对一)

Entityframework 6:如何将自定义类型映射到 SQL 表

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