まず第一に、このケース クラスは悪い考えです。
case class BasicProfile()
ケースクラスはメンバー値で比較されますが、これには何もありません。また、Slick で同じ名前を使用しているため、名前も良くありません。混乱を招く可能性があります。
クラスについて
class User(...) extends BasicProfile(...){
...
def unapply(i:User):Tuple12[...]= Tuple12(...)
}
ケースクラスを自分でエミュレートすることは可能です。22フィールドの制限のためにそうしていますか?参考までに: Scala 2.11 はより大きなケース クラスをサポートしています。私たちはあなたがSport195で試みていることをやっていますが、注意すべき点がいくつかあります.
apply
(のコンパニオン オブジェクト) のunapply
メンバーである必要があります。は実際のメソッドではありませんが、Scala コンパイラによって自動的に生成されます。引数のリストを受け取るようなメソッドを、それらの引数の単一のタプルを取る関数に変えます。タプルは 22 列に制限されているため、. ただし、もちろん、自分で自動生成することもできますが、別の名前を付ける必要がある場合があります。object User
class 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
""}
User
Scala 製品にするために混合できる特性:
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 コード ジェネレーターに組み込む時間を見つけたいと思っています。