在SLICK中使用伴随对象映射投影

jan*_*ans 9 scala slick

我有嵌套的类/对象,并希望使用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
    }
}
Run Code Online (Sandbox Code Playgroud)

但编译失败了几个错误:"方法unapply定义了两次","模糊引用重载定义,两种方法都适用[...]匹配预期类型?" 和"重载方法值<>与替代"

我找到了这个对映射投影" scala slick方法到目前为止无法理解 "的优秀解释和" 用<>映射投影到Slick中的伴随对象的案例类 ",但没有一个建议的解决方案适合我.

Fai*_*aiz 19

而不是unapplyapply,你可以传递做你想做的lambdas:

  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 */)
Run Code Online (Sandbox Code Playgroud)

这样,从表行到案例类的映射保留在表定义中,并且case类保持为简单的case类,这也不算太糟糕.

另一种方法是不使用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))
}
Run Code Online (Sandbox Code Playgroud)

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

你会在一定程度上获得类似案例类的用法,但你可能会错过其他好东西,比如拥有equalstoString免费的实际案例类.我宁愿保留case类(及其默认值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))
}
Run Code Online (Sandbox Code Playgroud)

然后在你的表模式中:

def * = id ~ myInt ~ myString <> (Foo.fromRow _, Foo.toRow _)
Run Code Online (Sandbox Code Playgroud)

  • 如何在光滑2中做第一个选项? (5认同)