将模型映射到scala中的Model.type

时间:2018-03-26 11:06:42

标签: scala playframework

我认为,我被困在一个(相当)简单的问题上。我有这样的模型

 case class MyModel(
      id: Option[Int],
      title: String,
      backStepId: Option[Int] = None,
      backStep: Option[MyModel] = None,
      ...
 )

所以我必须在我的模型上使用backStep属性。我使用的第一个backStepId来保存数据并将其映射到另一个实例 MyModel。我使用backStep来验证传入的请求。我的特点看起来像这样:

trait MyClassComponent extends AnotherClassComponent {
  self: HasDatabaseConfigProvider[JdbcProfile] =>
  import profile.api._
  class MyClass(tag: Tag) extends Table[MyModel](tag, "MyClass") {
    def id: Rep[Int] = column[Int]("id", O.PrimaryKey, O.AutoInc)
    def title: Rep[String] = column[String]("title")
    def backStepId: Rep[Option[Int]] = column[Option[Int]]("backStepId")
    def * : ProvenShape[MyModel] = (id.?, title, backStepId) <> ( {
      tuple: (Option[Int], String, Option[Int]) => MyModel(tuple._1, tuple._2, tuple._3, Some(<What do I need to fill in here?>))
    }, {
      x: MyModel=> Some((x.id, x.title, x.backStepId))
    })
  }
  val myModels: TableQuery[MyClass] = TableQuery[MyClass] // Query Object
}

填写MyModel时,它会说:Type mismatch, expected: Option[MyModel], actual: Some[MyModel.type]。但是我也将这种方法用于其他用例。例如Some(Seq()),每当我验证传入时 某些模型的数组/序列。 我在这做错了什么?提前谢谢!

1 个答案:

答案 0 :(得分:1)

首先让我们总结一下,你想在这里实现的目标:

  • 我猜这些错误来自Some(MyModel),它将伴侣对象实例放在一个Option中(MyModel.type是该伴随对象的一种类型)
  • 您希望MyModel具有递归定义(因为它引用自身),
  • 您想要从数据库中获取它并将其填充,
  • 显然你想要一个统一的模特。

我想说这样做会很困难(而且很危险)。如果您的backStep会创建,例如数据库中的循环依赖,你最终会得到fetch上的无限循环,因为ProvenShape里面没有比逻辑更复杂的地方,而是将元组来回映射到其他表示(并且解析另一个记录是更复杂的逻辑)。 p>

相反,我建议您将模型分为两部分:

case class MyModelRow(
    id: Option[Int],
    title: String,
    backStepId: Option[Int] = None,
    ...
)

case class MyModel(
    id: Int,
    title: String,
    backStep: Option[MyModel] = None,
      ...
)

这样,您可以抓取MyModelRow,然后将其翻译为MyModel

由于Slick(据我所知)不支持递归查询,您需要使用SQL to define your query

通过此类查询,您将获得Seq[MyModelRow]。使用该seq,您可以将Row无需依赖项转换为Model,然后使用Row引用它并将其转换为模型引用新构建模型等等。

事情是,这不是一个简单的问题。想想这样的情况:

Model(id:234).backStep -> Model(id:6456).backStep -> Model(id:56756).backStep -> null

您使用unapply建模的是,如果您抓取Model(id:234),则应该Model(id:6456)。除了持有假设,而这些假设必须持有Model(id:56756)。你可能想要它。你可能不会。当然,我会谨慎地将其作为默认行为。

相反,您可能会考虑默认不提取deps。只需获取backStepId并确定一旦到达该怎么办。对于那些特殊情况,当您确实需要所有依赖项设计一个单独的查询时 - 此查询可以使用原始SQL一次获取所有行,然后您可以手动链接它们。

如果性能无关紧要,而您希望获得类似Hibernate的良好体验,则可以创建扩展方法,使用Slick添加backStep方法以获取依赖关系{{1} }。

您可能想要检查的其他选项,就是让unapply始终返回Future[Option[MyModel]] None,并添加单独的服务以“丰富它”。

因此,根据权衡和优先级,您可能希望采用不同的路线。你知道你最好使用案例,所以我建议创建一个原型分支并试验哪种方法(也许我没想到的)将是最有用的。就个人而言,我更喜欢复杂的递归查询,以提醒我,我不能只是通过电话垃圾邮件数据库而不会受到任何惩罚。