私は Scala、Scalatra、Squeryl を使用した最初の実質的なプロジェクトに取り組んでおり、次の問題に遭遇しました。基本的な CRUD 操作 (作成、読み取り、更新、削除)、そのため、上記の抽象基本クラスがどのテーブルを参照するかを認識する方法が必要でした。
Squeryl では、データ クラスを squeryl.Schema を拡張するシングルトン オブジェクト内の実際のテーブルにマップします。一般に、DAO は各クラスのコンパニオン オブジェクトです。
タイプタグを使用して次のソリューションを思いつきました。
最初に、すべての DAO が継承する基本クラスの抜粋 (注: DBRecord は Squeryl の KeyedEntity のサブです):
abstract class CrudOps[S <: DBRecord](implicit tt: TypeTag[S]) {
def create(item: S)= {
inTransaction{
val result = ATSchema.recordTable.insert(item)
}
}
次に、ATSchema の recordTable 関数:
object ATSchema extends Schema {
val users = table[User]
def recordTable[T <: DBRecord](implicit tt: TypeTag[T]): Table[T] = tt.tpe match {
case t if t =:= typeOf[User] => users.asInstanceOf[Table[T]]
//...other table types go here
case _ => throw new IllegalArgumentException("Unknown DBRecord type")
}
}
さて、これは機能します。いくつかのテーブルがあり、CrudOps は適切なテーブルを取得して処理を行います。しかし、私が理解していないことがあります (私はまだ Scala にかなり慣れていません): recordTable() のテーブル val を Table[T] にキャストする必要があるのはなぜですか? .asInstanceOf を削除すると、タイプの不一致が発生しますが、users のタイプは Table[User] です...不要なはずです。また、これは些細な問題に対する複雑な解決策のように感じられ (おそらく型システムを悪用しているのかもしれません)、CrudOps をスキーマに結合します (これは避けたいと思います)。私よりScalaやSquerylの経験が豊富な人からの提案:)