代码之家  ›  专栏  ›  技术社区  ›  Felix

将模型映射到模型。键入scala

  •  0
  • Felix  · 技术社区  · 7 年前

    我想,我陷入了一个(相当)简单的问题。我有一个这样的模型

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

    所以我必须在我的模型上后退属性。第一个 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] 。然而,我也将这种方法用于其他用例。例如,每当我验证传入 某型号的数组/序列。 我做错了什么?提前感谢!

    1 回复  |  直到 7 年前
        1
  •  1
  •   Mateusz Kubuszok    7 年前

    首先,让我们总结一下,您希望在这里实现的目标:

    • 我猜错误来自 Some(MyModel) 将伴生对象实例放入选项中( MyModel.type 是该伴生对象的一种类型)
    • 你想要 MyModel 使用递归定义(因为它引用自身),
    • 您想从数据库中获取它,并且已经填充了它,
    • 显然你想要一个统一的模型。

    我要说的是,这样做很难(也很危险)。如果您的 backStep 如果在数据库中创建循环依赖关系,则在获取时会出现无限循环,因为在ProvenShape中没有比来回将元组映射到其他表示形式更复杂的逻辑了(解析另一条记录是更复杂的逻辑)。

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

    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,您可以获取没有依赖项的行,将其转换为模型,然后获取引用它的行,并将其转换为引用新构建模型的模型,等等。

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

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

    您使用unapply建模的是,如果 Model(id:234) 它应该有 Model(id:6456) 。除了保持假设 Model(id:56756) 。你可能想要它。你可能不会。当然,我会小心地将其作为默认行为。

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

    如果性能不重要,而你想拥有漂亮的(?)类似于Hibernate的体验,您可以创建扩展方法 后退 方法使用Slick将依赖项提取为 Future[Option[MyModel]]

    您可能希望检查的另一个选项是简单地让unapply始终返回 None 对于 后退 ,并添加单独的“丰富it”服务。

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