1

私は 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の経験が豊富な人からの提案:)

4

1 に答える 1

2

それは本当に Squeryl のものではありません。私が理解しているように、問題は、型消去が発生した後、実行時にパターン一致テストが行​​われることです。Scala は TypeTag を使用して型情報を保持し、実行時チェックを実行できますが、コンパイル時に型が正しいかどうかを推測することはできません。あなたが何かを試してみたら

case t: ClassTag[User] => users

これはコンパイラに静的チェックを行うように要求しているため、ユーザー型が消去されているという警告が表示されます。型を確認した後にキャストを実行しても問題ないはずなので、あなたのやり方はうまくいくはずです。より良い方法はないと思います。

于 2013-09-06T12:51:11.097 に答える