10

我有嵌套的类/对象,并希望使用 SLICK 在数据库中存储(和检索)它们。我知道使用 SLICK 映射投影将是关键。此外,我使用伴随对象在嵌套对象和平面结构之间进行映射(存储在 DB 表中)。我想做这样的事情(简化示例):

case class Foo(id: Int, myBar: Bar)

case class Bar(myInt: Int, myString: String)

object Foo {
  def apply(id: Int, myInt: Int, myString: String): Foo = Foo(id, Bar(myInt, myString))

  override def unapply(f: Foo) = (f.id, f.myBar.myInt, f.myBar.myString)
}

object TTable extends Table[Foo]("FOO") {
    def id = column[Int]("id",  O.PrimaryKey)
    def myInt = column[Int]("myInt", O NotNull)
    def myString = column[String]("myString", O NotNull)

    def * = id ~ myInt ~ myString <> (Foo.apply _, Foo.unapply _)

    def query(db: Database, id: Int): Option[Foo] = db withSession { //s: Session =>
        (for { b <- TTable if b.id is id} yield b).firstOption
    }
}

但是编译失败并出现几个错误:“方法 unapply 定义了两次”,“对重载定义的模糊引用,两个方法都应用 [...] 匹配预期类型?” 和“重载方法值 <> 与替代品”

我发现映射投影“我目前无法理解的 scala slick 方法”和“映射投影与 <> 到带有 Slick 中伴随对象的案例类”的出色解释,但建议的解决方案都不适合我。

4

1 回答 1

20

而不是unapplyand apply,您可以只传递执行您想要的操作的 lambda:

  def * = id ~ myInt ~ myString <> (
    (id,myInt,myString) => Foo(id, Bar(myInt, myString)),    /* from a row to a Foo */
    (f:Foo) => Some((f.id, f.myBar.myInt, f.myBar.myString)) /* and back */)

这样,从表行到案例类的映射保留在表定义中,案例类保留为简单案例类,这还不错。

另一种方法是不使用 case 类Foo,而是使用常规类,这样您就可以自由定义自己的对象applyunapply伴随对象,如下所示:

// untested code
class Foo private (val id: Int, val myBar: Bar) 
case class Bar(myInt: Int, myString: String)
object Foo {
  def apply(id: Int, myInt: Int, myString: String): Foo = new Foo(id, Bar(myInt, myString))
  def unapply(f: Foo) = Some((f.id, f.myBar.myInt, f.myBar.myString))
}

如果你想做def * = id ~ myInt ~ myString <> (Foo.apply _, Foo.unapply _)

您将在一定程度上获得类似案例类的用法,但您可能会错过其他好东西,例如拥有equalstoString免费的实际案例类。我宁愿保留 case 类(以及它们的 default apply unapply),以便在正常约定中将它们视为代数数据类型。

这里真正的问题是案例类有自己的unapply,所以你不能(据我所知)在你的同伴类中有类似的方法(相同的名称和相同的参数)。您可以简单地使用另一个方法名称。毕竟,你想做的在语义上并不等同于unapply

object Foo {
  def fromRow(id: Int, myInt: Int, myString: String): Foo = Foo(id, Bar(myInt, myString))
  def toRow(f: Foo) = Some((f.id, f.myBar.myInt, f.myBar.myString))
}

然后在您的表架构中:

def * = id ~ myInt ~ myString <> (Foo.fromRow _, Foo.toRow _)
于 2013-03-26T06:18:11.790 回答