0

以前はケースクラスを使ってクラスオブジェクトをslick2用のデータに変換していましたが、現在は別のplayプラグインを使用しており、プラグインオブジェクトはケースクラスを使用しており、私のクラスはこのケースクラスから継承されています。ですので、ケースクラス固有のケースクラスにscala言語禁止のユースケースクラスとしてケースクラスを使用することはできません。

前:

case class User()

class UserTable(tag: Tag) extends Table[User](tag, "User") {
  ...
  def * = (...)<>(User.tupled,User.unapply)
}

できます。しかし今、私は上から下に変更する必要があります:

case class BasicProfile()

class User(...) extends BasicProfile(...){
  ...
  def unapply(i:User):Tuple12[...]= Tuple12(...)
}
class UserTable(tag: Tag) extends Table[User](tag, "User") {
  ...
  def * = (...)<>(User.tupled,User.unapply)
}

自動生成されたケースクラステンプレートのように、tupled と unapply(私の書き方が正しいかどうかではない) メソッドの書き方がわかりません。または、slick2 でクラスを talbe にマッピングする別の方法を教えてください。

誰でもその例を教えてもらえますか?

4

1 に答える 1

0

まず第一に、このケース クラスは悪い考えです。

case class BasicProfile()

ケースクラスはメンバー値で比較されますが、これには何もありません。また、Slick で同じ名前を使用しているため、名前も良くありません。混乱を招く可能性があります。

クラスについて

class User(...) extends BasicProfile(...){
  ...
  def unapply(i:User):Tuple12[...]= Tuple12(...)
}

ケースクラスを自分でエミュレートすることは可能です。22フィールドの制限のためにそうしていますか?参考までに: Scala 2.11 はより大きなケース クラスをサポートしています。私たちはあなたがSport195で試みていることをやっていますが、注意すべき点がいくつかあります.

apply(のコンパニオン オブジェクト) のunapplyメンバーである必要があります。は実際のメソッドではありませんが、Scala コンパイラによって自動的に生成されます。引数のリストを受け取るようなメソッドを、それらの引数の単一のタプルを取る関数に変えます。タプルは 22 列に制限されているため、. ただし、もちろん、自分で自動生成することもできますが、別の名前を付ける必要がある場合があります。object Userclass User.tupled.apply.tupled

Slick コード ジェネレーターを twirl テンプレート エンジンと組み合わせて使用​​しています (@式を挿入するために使用します。$生成された Scala コードに挿入され、生成されたコードがコンパイル/実行されるときに評価されます)。ここにあなたを助けるかもしれないいくつかのスニペットがあります:

適用メソッドの生成

  /** Factory for @{name} objects
    @{indentN(2,entityColumns.map(c => "* @param "+c.name+" "+c.doc).mkString("\n"))}
    */
  final def apply(
    @{indentN(2,
        entityColumns.map(c =>
          colWithTypeAndDefault(c)
        ).mkString(",\n")
    )}
  ) = new @{name}(@{columnsCSV})

unapply メソッドを生成します。

@{if(entityColumns.size <= 22)
  s"""
  /** Extractor for ${name} objects */
  final def unapply(o: ${name}) = Some((${entityColumns.map(c => "o."+c.name).mkString(", ")}))
  """.trim
  else
  ""}

UserScala 製品にするために混合できる特性:

trait UserBase with Product{
  // Product interface
  def canEqual(that: Any): Boolean = that.isInstanceOf[@name]
  def productArity: Int = @{entityColumns.size}
  def productElement(n: Int): Any = Seq(@{columnsCSV})(n)

  override def toString = @{name}+s"(${productIterator.toSeq.mkString(",")})"
...

ケースクラスのような.copyメソッド

  final def copy(
    @{indentN(2,columnsCopy)}
  ): @{name} = @{name}(@{columnsCSV})

これらのクラスを Slick で使用するには、いくつかのオプションがあります。すべてがやや新しく、文書化されていません (まあ)。通常の<>演算子 Slick はタプルを経由しますが、それは 22 列を超えるオプションではありません。1 つのオプションは、新しい高速パス コンバーターです。別のオプションは、Slick HList によるマッピングです。どちらにも例はありません。もう 1 つのオプションは、カスタム形状を使用することです。これが私たちが行っていることです。これには、クラスのカスタム形状を定義し、型をUser使用して定義された別のクラスを定義してColumn、クエリ内でユーザーをミラーリングする必要があります。このように: http://slick.typesafe.com/doc/2.1.0/api/#scala.slick.lifted.ProductClassShape手で書くには冗長すぎます。これには、次のテンプレート コードを使用します。

/** class for holding the columns corresponding to @{name}
 * used to identify this entity in a Slick query and map
 */
class @{name}Columns(
  @{indent(
    entityColumns
      .map(c => s"val ${c.name}: Column[${c.exposedType}]")
      .mkString(", ")
  )}
) extends Product{
  def canEqual(that: Any): Boolean = that.isInstanceOf[@name]
  def productArity: Int = @{entityColumns.size}
  def productElement(n: Int): Any = Seq(@{columnsCSV})(n)
}

/** shape for mapping @{name}Columns to @{name} */
object @{name}Implicits{
  implicit object @{name}Shape extends ClassShape(
    Seq(@{
      entityColumns
        .map(_.exposedType)
        .map(t => s"implicitly[Shape[ShapeLevel.Flat, Column[$t], $t, Column[$t]]]")
        .mkString(", ")
    }),
    vs => @{name}(@{
      entityColumns
        .map(_.exposedType)
        .zipWithIndex
        .map{ case (t,i) => s"vs($i).asInstanceOf[$t]" }
        .mkString(", ")
    }),
    vs => new @{name}Columns(@{
      entityColumns
        .map(_.exposedType)
        .zipWithIndex
        .map{ case (t,i) => s"vs($i).asInstanceOf[Column[$t]]" }
        .mkString(", ")
    })
  )
}
import @{name}Implicits.@{name}Shape

Slick コード ジェネレーターに追加したいくつかのヘルパー:

  val columnsCSV = entityColumns.map(_.name).mkString(", ")
  val columnsCopy = entityColumns.map(c => colWithType(c)+" = "+c.name).mkString(", ")
  val columnNames = entityColumns.map(_.name.toString)


  def colWithType(c: Column) = s"${c.name}: ${c.exposedType}"

  def colWithTypeAndDefault(c: Column) =
    colWithType(c) + colDefault(c).map(" = "+_).getOrElse("")

  def indentN(n:Int,code: String): String = code.split("\n").mkString("\n"+List.fill(n)(" ").mkString(""))

特に Scala を初めて使用する場合は、これを再現するのが少し面倒かもしれません。いつか公式の Slick コード ジェネレーターに組み込む時間を見つけたいと思っています。

于 2014-08-05T15:56:19.543 に答える