1

我正在使用 Scala、Scalatra 和 Squeryl 进行我的第一个实质性项目,并遇到了以下问题:我想为我的 DAO 提供一个抽象基类,它提供了基本 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,我会得到类型不匹配,但用户的类型是 Table[User]... 似乎应该是不必要的。此外,这给人一种对应该是微不足道的问题的复杂解决方案的感觉(也许我在滥用类型系统),并且还将 CrudOps 与 Schema 结合起来(我想避免),所以我当然愿意来自比我有更多 Scala 和/或 Squeryl 经验的人的建议:)

4

1 回答 1

2

这不是真正的 Squeryl 事情。据我了解,问题在于模式匹配测试是在运行时完成的,在发生类型擦除之后。Scala 能够通过 TypeTag 保留类型信息并执行运行时检查,但它不能在编译时推断类型是正确的。如果你要尝试类似的东西

case t: ClassTag[User] => users

这是要求编译器进行静态检查,您会收到用户类型已删除的警告。您这样做的方式应该可以工作,因为在您验证类型之后执行强制转换应该没问题,而且我认为没有更好的方法。

于 2013-09-06T12:51:11.097 回答