如何在Typesafe的Slick中给定Seq [TableQuery]创建表格?

时间:2014-01-22 05:49:23

标签: scala slick

尝试使用表格填充数据库时遇到问题(使用Slick 2.0.0):

import scala.slick.driver.JdbcDriver
import scala.slick.lifted.TableQuery

case class DemoInit(slickDriver:JdbcDriver, tables:Seq[TableQuery[_]]) {
  lazy val db = slickDriver.simple.Database.forURL("jdbc_url", "user", "pass", driver = "com.example.Driver")

  import slickDriver.simple.{tableQueryToTableQueryExtensionMethods, ddlToDDLInvoker}

  def init() {
    db withSession { implicit session =>
      tables.map(_.ddl).reduce(_ ++ _).create
    }
  }
}

尝试编译上面的代码会导致以下两个错误:

value ddl is not a member of scala.slick.lifted.TableQuery[_$1]

value create is not a member of scala.slick.lifted.TableQuery[_$1]

我猜测类型参数没有被正确推断。我做错了什么?

2 个答案:

答案 0 :(得分:3)

您需要为表类型添加正确的约束:

tables: Seq[TableQuery[_ <: Table[_]]]

在没有采用您期望的隐式转换的情况下,添加对此转换的显式调用会有所帮助。这将为您提供更好的错误消息,解释转换不适用的原因。

然后您将遇到您使用reduce错误的下一个问题。您可能希望使用类似tables.map(_.ddl).reduce(_ ++ _)的内容。

由于Table与路径有关,因此您无法将其用于尝试将所有内容作为参数传递给类的设置。虽然允许您在def的后续参数列表中引用先前参数列表中的路径相关类型,但这在class中是不可能的。您必须以不同方式构造代码以使路径依赖类型正确,例如:

  import scala.slick.driver.JdbcProfile

  class DemoDAO(val slickDriver: JdbcProfile) {
    import slickDriver.simple._
    lazy val db = slickDriver.simple.Database.forURL("jdbc_url", "user", "pass", driver = "com.example.Driver")

    def init(tables: Seq[TableQuery[_ <: Table[_]]]) {
      db withSession { implicit session =>
        tables.map(_.ddl).reduce(_ ++ _).create
      }
    }
  }
}

答案 1 :(得分:2)

我最终做的是创造一个新的特性:

import scala.slick.driver.JdbcProfile

trait TablesSupplier {
  def tables(profile:JdbcProfile):Seq[JdbcProfile#SimpleQL#TableQuery[_ <: JdbcProfile#SimpleQL#Table[_]]]
}

我正在使用Slick生成表对象的源代码,因此我有一个Tables特征,我在TablesSupplier的实现中使用它:

import scala.slick.driver.JdbcProfile

object DemoTablesSupplier extends TablesSupplier {
  def tables(profile:JdbcProfile) = {
    val _profile = profile
    val demoTables = new Tables { val profile = _profile }
    import demoTables._
    Seq(Table1, Table2, Table3)
  }
}

所以,我的DemoInit现在看起来像这样:

import scala.slick.driver.JdbcDriver

case class DemoInit(slickDriver:JdbcDriver, tables:Seq[TableQuery[_]]) {
  lazy val db = slickDriver.simple.Database.forURL("jdbc_url", "user", "pass", driver = "com.example.Driver")

  import slickDriver.simple.{tableQueryToTableQueryExtensionMethods, ddlToDDLInvoker}

  def init() {
    db withSession { implicit session =>
      val profile = slickDriver.profile
      //import the type of Table and TableQuery that are expected as well as two implicit methods that are necessary in order to use 'ddl' and 'create' methods
      import profile.simple.{Table, TableQuery, tableQueryToTableQueryExtensionMethods, ddlToDDLInvoker}
      //using asInstanceOf is very ugly but I couldn't figure out a better way
      val tables = tablesCreator.tables(profile).asInstanceOf[Seq[TableQuery[_ <: Table[_]]]]
      tables.map(_.ddl).reduce(_ ++ _).create
    }
  }
}