使用Slick 2.0进行通用的CRUD操作

4

我正在尝试为Slick 2.0编写一个通用的CRUD trait。这个trait应该 a) 提供通用的方法,以读取/更新/删除实体,以及 b) 抽象出数据库。参考这个slick示例(数据库抽象)和这篇文章(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操作的进一步阅读参考资料。

如果您使用Table而不是AbstractTable,它就能正常工作,但是为此,您需要一个具体的Profile。我对slick 2.0中的配置文件如何使用感到困惑。 - poroszd
1个回答

2

TableElementType 类型是在 class AbstractTable[A] 内部定义的抽象类型。Scala 并不知道 ATableElementType 之间的任何关系。然而,class Table 定义了 final type TableElementType = A,这告诉 Scala 这种关系存在(而且显然 Scala 聪明到足够利用 final 注解来知道这种关系即使对于一个子类型 T <: Table[A] 也成立,尽管 Table[A]A 上并不协变)。

因此,你需要使用 T <: Table[A] 而不是 T <: AbstractTable[A]。由于 Table 在 Slick 驱动程序中作为“蛋糕”(即蛋糕模式)的一部分,你还需要将 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
    }
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接