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

しかし、コンパイルはいくつかのエラーで失敗します。および「オーバーロードされたメソッド値<>と代替手段」

マップされた射影のこの優れた説明「これまで理解できなかったscala slick method」と「Slickのコンパニオンオブジェクトを持つケースクラスへの<>によるマップされた射影」を見つけましたが、提案された解決策はどれもうまくいきません。

4

1 に答える 1

20

unapplyandの代わりにapply、必要なことを行うラムダを渡すことができます。

  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 */)

このように、テーブル行からケース クラスへのマッピングはテーブル定義にとどまり、ケース クラスは単純なケース クラスのままになります。これはそれほど悪いことではありません。

もう 1 つの方法は、 のケース クラスを使用せず、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 _)

ケースクラスのような使用法をある程度得ることができますが、実際のケースクラスのように無料で使用できるなど、他の優れたものを見逃す可能性がありequalsますtoStringapply 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 に答える