我有嵌套的类/对象,并希望使用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定义了两次”,“对重载定义的模糊引用,两种方法都适用[...]匹配期望类型?”和“重载方法值&lt;&gt;与替代品”
我发现了对映射投影“scala slick method I can not understand so far”和“Mapped projection with <> to a case class with companion object in Slick”的这种出色解释,但没有一个建议的解决方案对我有效。
答案 0 :(得分:19)
而不是unapply
和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类保持为简单的case类,这不是太糟糕。
另一种方法是不使用Foo
的案例类,而是使用常规类,让您可以在随播对象中自由定义自己的apply
和unapply
,像这样:
// 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 _)
你会在一定程度上获得类似案例类的用法,但你可能会错过其他好东西
比如实际案例类免费equals
和toString
。
我宁愿保留案例类(及其默认的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 _)