我正在使用光滑的3.1.0实现一个根据需要创建表的函数,如下所示:
def ensureTables(db: backend.DatabaseDef, ts: Seq[TableQuery[_]]) {
val ts0 = Await.result(db.run(MTable.getTables), Duration.Inf)
val ns = Set() ++ ts0.map(t => t.name.name)
for {
t <- ts
} Await.result(db.run(t.schema.create), Duration.Inf)
}
由于编译错误,它还没有完成(我想在for表达式中添加过滤器)。错误发生在第七行:value schema is not a member of slick.driver.SQLiteDriver.api.TableQuery[_$1]
。这是因为SQLiteDriver.API
(在这种情况下为tableQueryToTableQueryExtensionMethods
)中定义的隐式函数未包括在内。
如何正确包含这些隐式功能?
答案 0 :(得分:2)
当我想使用不同的驱动程序插入我的db代码时,我通常使用配置文件类型参数化我的函数(或traits / classes)并提供配置文件作为参数;在你的情况下,函数看起来像这样:
def ensureTables[P <: JdbcProfile](profile: P)(db: profile.api.Database, ts: Seq[TableQuery[_]]) {
import profile.api._
...
}
如果函数位于聚合数据库相关函数的特征或类中,则可以在类级别提供配置文件并在那里导入。
顺便说一句,请注意您每次使用Await
时都会阻塞两个线程并可能导致死锁;使用像flatMap
这样的未来组合器代替编写异步代码。
答案 1 :(得分:1)
<强> TL;博士强>
注意:这不是一个新的答案,它只详细阐述了Aldo Stracquadanio提供的答案。这是一个答案,以便以友好的方式显示更多细节。
首先,我尝试了以下版本,这是简单应用Aldo提示的结果:
def ensureTables[P <: JdbcProfile]
(profile: P)
(db: profile.api.Database, ts: Seq[TableQuery[_]]) {
import profile.api._
val ts0 = Await.result(db.run(MTable.getTables), Duration.Inf)
val ns = Set() ++ ts0.map(t => t.name.name)
for (t <- ts) Await.result(db.run(t.schema.create), Duration.Inf)
}
错误仍然存在,因为ts
的类型错误:tableQueryToTableQueryExtensionMethods
所需的类型为Query[T, U, Seq] with TableQuery[T]
,而不是TableQuery[_]
,因此没有任何含义符合条件对于上述定义。
ensureTables
的正确版本应实现为:
def ensureTables[P <: RelationalProfile, T <: RelationalProfile#Table[_], C[_]]
(profile: P)
(db: profile.api.Database,
ts: Seq[Query[T, _, C] with TableQuery[T]]) {
import profile.api._
val ts0 = Await.result(db.run(MTable.getTables), Duration.Inf)
val ns = Set() ++ ts0.map(t => t.name.name)
for (t <- ts) Await.result(db.run(t.schema.create), Duration.Inf)
}
此函数本身编译。但是,当我尝试将多个TableQuery
值放在一起并使用它时,我得到了两个新错误:
ensureTables(profile)(db, Seq(circles, rectangles))
导致
[error] SlickProg.scala:40: no type parameters for method ensureTables: (db: slick.driver.SQLiteDriver.profile.api.Database, ts: Seq[slick.driver.SQLiteDriver.api.Query[T, _, C] with slick.driver.SQLiteDriver.api.TableQuery[T]])Unit exist so that it can be applied to arguments (slick.driver.SQLiteDriver.backend.DatabaseDef, Seq[slick.lifted.TableQuery[_ >: slab.Rectangles with slab.Circles <: slick.driver.SQLiteDriver.Table[_ >: (Int, Double, Double, Double, Double, Double) with (Int, Double, Double, Double) <: Product with Serializable]]])
[error] --- because ---
[error] argument expression's type is not compatible with formal parameter type;
[error] found : Seq[slick.lifted.TableQuery[_ >: slab.Rectangles with slab.Circles <: slick.driver.SQLiteDriver.Table[_ >: (Int, Double, Double, Double, Double, Double) with (Int, Double, Double, Double) <: Product with Serializable]]]
[error] required: Seq[slick.driver.SQLiteDriver.api.Query[?T, _, ?C] with slick.driver.SQLiteDriver.api.TableQuery[?T]]
[error] (which expands to) Seq[slick.lifted.Query[?T, _, ?C] with slick.lifted.TableQuery[?T]]
[error] ensureTables(profile)(db, Seq(circles, rectangles))
[error] ^
[error] SlickProg.scala:40: type mismatch;
[error] found : Seq[slick.lifted.TableQuery[_ >: slab.Rectangles with slab.Circles <: slick.driver.SQLiteDriver.Table[_ >: (Int, Double, Double, Double, Double, Double) with (Int, Double, Double, Double) <: Product with Serializable]]]
[error] required: Seq[slick.driver.SQLiteDriver.api.Query[T, _, C] with slick.driver.SQLiteDriver.api.TableQuery[T]]
[error] (which expands to) Seq[slick.lifted.Query[T, _, C] with slick.lifted.TableQuery[T]]
[error] ensureTables(profile)(db, Seq(circles, rectangles))
[error] ^
[error] two errors found
这是由于将不同类型的值放入单个序列中导致意外类型的序列。编译器为序列的元素计算了一个公共类型(_ >: slab.Rectangles with slab.Circles <: slick.driver.SQLiteDriver.Table[_ >: (Int, Double, Double, Double, Double, Double) with (Int, Double, Double, Double) <: Product with Serializable]
)。
我最终得到以下实现,从ensureTable
函数外部迭代表:
def ignore[T](x: T): Unit = ()
def valueOf[T](f: Future[T]): T = Await.result(f, Duration.Inf)
def ensureTable[P <: RelationalProfile, T <: RelationalProfile#Table[_], C[_]]
(p: P)
(db: p.api.Database, ns: Set[String],
t: Query[T, _, C] with TableQuery[T]) {
import p.api._
val n = t.shaped.value.tableName
if (!ns.contains(n))
ignore(valueOf(db.run(t.schema.create)))
}
def tablesOf[P <: RelationalProfile](p: P)(db: p.api.Database): Seq[MTable] =
valueOf(db.run(MTable.getTables))
val names = Set() ++ tablesOf(profile)(db).map(_.name.name)
for (t <- Seq(circles, rectangles)) ensureTable(profile)(db, names, t)
谢谢Aldo Stracquadanio。