4

我正在尝试为 Slick 2.0 编写一个通用的 CRUD 特征。该特征应该a)提供通用方法来读取/更新/删除实体以及b)从数据库中抽象。按照这个漂亮的例子(数据库抽象)和这篇文章(CRUD trait),我想出了以下(缩短的)代码片段:

trait Profile {
  val profile: JdbcProfile
}

trait Crud[T <: AbstractTable[A], A] { this: Profile =>
  import profile.simple._

  val qry: TableQuery[T]

  def countAll()(implicit session: Session): Int = {
    qry.length.run
  }

  def getAll()(implicit session: Session): List[A] = {
      qry.list // <-- type mismatch; found: List[T#TableElementType] required: List[A]
  }
}

由于类型不匹配,代码无效。第二个函数的返回类型似乎是类型List[T#TableElementType],但需要是 List[A]。关于如何解决问题的任何想法。也欢迎对通用 Slick 2.0 操作的进一步阅读提供其他参考。

4

1 回答 1

2

type TableElementType在 中是抽象的class AbstractTable[A]。Scala 不知道A和之间的任何关系TableElementTypeclass Table另一方面,定义final type TableElementType = A,它告诉 Scala 这种关系(显然 Scala 足够聪明,可以使用final注释知道关系甚至适用于子类型,T <: Table[A]即使Table[A]在 中不是协变的A)。

所以你需要使用T <: Table[A]而不是T <: AbstractTable[A]. 并且因为Table在 Slick driver 蛋糕内(如蛋糕图案中),您还需要将 Crud 移动到蛋糕中。蛋糕是病毒式的。

trait Profile {
  val profile: JdbcProfile
}
trait CrudComponent{ this: Profile =>
  import profile.simple._

  trait Crud[T <: Table[A], A] {

    val qry: TableQuery[T]

    def countAll()(implicit session: Session): Int = {
      qry.length.run
    }

    def getAll()(implicit session: Session): List[A] = {
        qry.list // <-- works as intended
    }
  }
}
于 2014-03-11T23:49:10.680 回答