2013-03-26 81 views
9

我有嵌套的类/对象,并希望通过使用SLICK将它们存储(并检索)到数据库中。我明白,SLICK映射投影将是关键。此外,我使用伴侣对象来映射嵌套对象和平面结构(存储在数据库表中)。我想要做这样的事情(例如简化):映射投影与SLICK中的伴随对象

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 
    } 
} 

但是编译失败与几个错误:“方法不应用被定义了两次”,“暧昧参考超载的定义,无论是方法应用于[...]匹配预期类型?“和“过载方法值<>替代方案”

我发现了映射投影“scala slick method I can not understand so far”和“Mapped projection with <> to a case class with companion object in Slick”的优秀解释,但没有一个建议的解决方案适用于我。

回答

19

代替unapplyapply,你可以只通过在你想要什么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,但普通班,而不是它可让您自由定义的陪伴对象自己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免费与实际案例课。 我宁愿保留大小写类(和它们的默认值applyunapply),以便它们可以在常规约定中作为代数数据类型处理。

这里真正的问题是案例类有自己的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 _) 
+1

非常感谢。事实上,我更喜欢你的第一个解决方案工作得很好但是,大约有十几个参数,整个映射似乎有很多样板。我了解SLICK的直接嵌入将更加紧凑,但不允许插入。我期待看到SLICK将如何在这方面取得进展。 – jans 2013-03-29 01:54:16

+1

即使你可以用你的问题中描述的“apply”和“unapply”,你仍然必须处理好几十个参数吗? FWIW,看看我最后的编辑。 – Faiz 2013-03-29 05:08:52

+1

对于方法“应用”,使用案例类和上次编辑时,我得到“重载定义的模糊引用”错误。因此,我不得不将同伴对象中的方法重命名为“fromRow”。 – jans 2013-04-02 13:51:18