在Slick 2中,我们可以像这样映射表:

case class Cooler(id: Option[Int], minTemp: Option[Double], maxTemp: Option[Double])

/**
 * Define table "cooler".
 */
class Coolers(tag: Tag) extends Table[Cooler](tag, "cooler") {
  def id = column[Int]("id", O.PrimaryKey, O.AutoInc)
  def minTemp = column[Double]("min_temp", O.Nullable)
  def maxTemp = column[Double]("max_temp", O.Nullable)

  def * = (id.?, minTemp.?, maxTemp.?) <> (Cooler.tupled, Cooler.unapply _)
}

object Coolers {
  val tableQuery = TableQuery[Coolers]
}

因为我有很多表,所以我想为它们定义通用方法,例如finddeleteupdate,所以我必须在一个父类(super class)中定义这些方法,从那里扩展我的对象(object Coolers extends TableUtils[Coolers, Cooler])。为了定义这些方法,我需要tableQuery从这个父类(super class)中移出我的对象,因此我尝试了如下操作:
abstract class TableUtils[T <: Table[A] , A] {

val tableQuery = TableQuery[T]

}

但是我收到关于tableQuery定义的错误:
class type required but T found
有人知道我在做什么错吗?

最佳答案

当您执行TableQuery[T]时,实际上是在调用TableQuery.apply,即is actually a macro

该宏的主体尝试实例化T,但是在您的情况下T已成为编译器不知道如何实例化的(未知)类型参数。问题类似于尝试编译它:

def instantiate[T]: T = new T
// Does not compile ("class type required but T found")

最终结果是TableQuery.apply仅可用于具体类型。

可以来解决该using a type class to capture the call to TableQuery.apply (在知 Prop 体类型的时候)以及隐式宏,以提供该类型类的实例。然后,您将获得类似以下内容的信息:
abstract class TableUtils[T <: Table[A] : TableQueryBuilder, A] {
  val tableQuery = BuildTableQuery[T]
}

其中TableQueryBuilder是类型类,而BuildTableQueryTableQuery.apply的替代版本,它将转发到TableQueryBuilder实例以执行实际的实例化。

我已经添加了一个实现作为another answer here的一部分。

tableQuery声明为抽象值,并在TableUtils的每个具体派生类中定义它,将更加容易(如果不太方便):
abstract class TableUtils[T <: Table[A] , A] {
  val tableQuery: TableQuery[T, T#TableElementType]
  // define here your helper methods operating on `tableQuery`
}
object Coolers extends TableUtils[Coolers, Cooler] {
  val tableQuery = TableQuery[Coolers]
}

09-26 17:07